# GENERATED FILE. Do not edit.
#
# Projected from the Zod MCP tool registry in product/mcp/gs.mcp.
# Regenerate:  cd product/mcp/gs.mcp && pnpm openapi:public
# Verify:      cd product/mcp/gs.mcp && pnpm openapi:public:check
openapi: 3.0.3
info:
  title: "GetSales public contract: gs.service.playtables"
  description: |-
    The data platform and the outreach engine: tables of people and companies, their enrichment columns, cells and runs, the data sources that feed them, sender profiles, the stoplist, the activity feed, the credit ledger, and the multichannel workflows with their per-person journeys and tasks.

    GENERATED. This document is projected from the Zod MCP tool registry in `product/mcp/gs.mcp` (one tool per public endpoint, 1:1). Do not edit it by hand; edit the tool definition and regenerate with `pnpm openapi:public`.

    Surface: the public `/api` contract of `gs.service.playtables`, 142 operations. This is the only OpenAPI document the platform publishes. Internal (`/internal`) and health endpoints are deliberately absent: they are not part of any contract, they can change without notice, and the service source is their only description.

    Conventions:
    - Auth is a bearer JWT, optionally narrowed by the `Team-SID` header.
    - Every success body is an MCP envelope: `success: true` plus one typed `operation` shape (`search`, `get`, `create`, `update`, `delete`, `metrics`, `group_by`, `action`), and a `meta` block with `trace_id` for support.
    - Every failure is the same `McpError` envelope with a code from a fixed 16-code taxonomy, so a client maps errors once.
    - Lists page with `page_size` (0 to 500, default 50) plus an opaque forward `cursor`; `page_size: 0` returns counts only.
    - On `GET` and `DELETE`, object-valued query parameters (`filter`, `sort`) travel as JSON text and array-valued ones repeat as `name[]=value`.
    - The MCP-only `_meta` field (usage analytics) never reaches the backend and is not part of this contract.
  version: "1.0"
  contact:
    name: GetSales
    url: https://getsales.io
    email: support@getsales.io
  license:
    name: Proprietary
    url: https://getsales.io/terms
servers:
  - url: https://beta.getsales.io/playtables/v1
    description: Production (the gateway path on the beta ring; the origin is provisioned per DEPLOY_MAP.md)
security:
  - BearerJwt: []
    TeamSid: []
tags:
  - name: activities
    description: Registry package `mcp.playtables/activities`, served on MCP mount `playtables.journeys`.
  - name: activity_objects
    description: Registry package `mcp.playtables/activity_objects`, served on MCP mount `playtables.people`.
  - name: companies
    description: Registry package `mcp.playtables/companies`, served on MCP mount `playtables.people`.
  - name: credit_ledger_entries
    description: Registry package `mcp.playtables/credit_ledger_entries`, served on MCP mount `id.billing`.
  - name: data_source_items
    description: Registry package `mcp.playtables/data_source_items`, served on MCP mount `playtables.sources`.
  - name: data_sources
    description: Registry package `mcp.playtables/data_sources`, served on MCP mount `playtables.sources`.
  - name: notes
    description: Registry package `mcp.playtables/notes`, served on MCP mount `playtables.pipeline`.
  - name: people
    description: Registry package `mcp.playtables/people`, served on MCP mount `playtables.people`.
  - name: pipeline_stages
    description: Registry package `mcp.playtables/pipeline_stages`, served on MCP mount `playtables.pipeline`.
  - name: plays
    description: Registry package `mcp.playtables/plays`, served on MCP mount `playtables.pipeline`.
  - name: playtable_field_values
    description: Registry package `mcp.playtables/playtable_field_values`, served on MCP mount `playtables.columns`.
  - name: playtable_fields
    description: Registry package `mcp.playtables/playtable_fields`, served on MCP mount `playtables.columns`.
  - name: playtable_runs
    description: Registry package `mcp.playtables/playtable_runs`, served on MCP mount `playtables.columns`.
  - name: playtable_views
    description: Registry package `mcp.playtables/playtable_views`, served on MCP mount `playtables.tables`.
  - name: playtables
    description: Registry package `mcp.playtables/playtables`, served on MCP mount `playtables.tables`.
  - name: result_pages
    description: Registry package `mcp.playtables/result_pages`, served on MCP mount `playtables.tables`.
  - name: sender_profiles
    description: Registry package `mcp.playtables/sender_profiles`, served on MCP mount `playtables.sources`.
  - name: stoplist_entries
    description: Registry package `mcp.playtables/stoplist_entries`, served on MCP mount `playtables.stoplist`.
  - name: tags
    description: Registry package `mcp.playtables/tags`, served on MCP mount `playtables.pipeline`.
  - name: workflow_attachments
    description: Registry package `mcp.playtables/workflow_attachments`, served on MCP mount `playtables.workflows`.
  - name: workflow_records
    description: Registry package `mcp.playtables/workflow_records`, served on MCP mount `playtables.journeys`.
  - name: workflow_sources
    description: Registry package `mcp.playtables/workflow_sources`, served on MCP mount `playtables.workflows`.
  - name: workflow_tasks
    description: Registry package `mcp.playtables/workflow_tasks`, served on MCP mount `playtables.journeys`.
  - name: workflow_versions
    description: Registry package `mcp.playtables/workflow_versions`, served on MCP mount `playtables.workflows`.
  - name: workflows
    description: Registry package `mcp.playtables/workflows`, served on MCP mount `playtables.workflows`.
paths:
  /api/activities/metrics:
    post:
      operationId: get_activities_metrics
      summary: Activities metrics
      description: |-
        Period-bound engagement aggregates over the activity feed. period is required (half-open [from, to) on occurred_at; occurred_at operators inside filter are ignored, created_at ones apply); group_by category | type | object_type adds per-group counts and metrics. Returns first_occurred_at, last_occurred_at and active_days_count; per-kind counts ride aggregated.counts.groups. Row-level history: search_activities.

        Contract:
        - MCP tool `get_activities_metrics`, registry package `mcp.playtables/activities`, mount `playtables.people`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - activities
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetActivitiesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetActivitiesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_activities_metrics
      x-gs-mcp-mount: playtables.people
      x-gs-entity: activities
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/activities/search:
    post:
      operationId: search_activities
      summary: Search activities
      description: |-
        The append-only event feed of a person or company: channel, website and profile-view facts (private context, never repeated to the lead), workflow, object, tag and note changes. Scope with object_sid (the timeline), playtable_sid, play_sid, sender_profile_sid or involved_workflow_sid; created_at is when a fact reached the ledger; page_size 0 = counts.groups alone. Includes: person, company, play_acts, person_journey. Not for message bodies or workflow state.

        Contract:
        - MCP tool `search_activities`, registry package `mcp.playtables/activities`, mount `playtables.people`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - activities
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchActivitiesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchActivitiesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_activities
      x-gs-mcp-mount: playtables.people
      x-gs-entity: activities
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/activities/{sid}/act:
    post:
      operationId: act_on_activity
      summary: Act on activity
      description: |-
        Act by hand on a feed event: like or comment on a post event, or send_message to the person of any event. Bears a user task that goes scheduled now through the sender profile's scheduler and limits, posting on LinkedIn as the sender profile: confirm the words and the sender with the user first. A repeat answers the existing task (already_acting). A failed act waits under its event (retry or cancel the task). The words a play would write: draft_for_activity.

        Contract:
        - MCP tool `act_on_activity`, registry package `mcp.playtables/activities`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - activities
      parameters:
        - name: sid
          in: path
          required: true
          description: The event (cr_ac_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ac_
            description: The event (cr_ac_…).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ActOnActivityRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActOnActivityResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: act_on_activity
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: activities
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/activities/{sid}/draft:
    post:
      operationId: draft_for_activity
      summary: Draft for activity
      description: |-
        The words a play would write for an event, nothing created: a comment on a post event (the AI reads the whole post under the table's Engage with posts brief; one AI call at the AI price, a fresh draft each time) or a message to the person (the moment's template for a birthday, anniversary or job change, rendered for the person). An event no writer covers answers an empty text. Show the words to the user, then act_on_activity with them as they are or edited.

        Contract:
        - MCP tool `draft_for_activity`, registry package `mcp.playtables/activities`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - activities
      parameters:
        - name: sid
          in: path
          required: true
          description: The event (cr_ac_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ac_
            description: The event (cr_ac_…).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DraftForActivityRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DraftForActivityResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: draft_for_activity
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: activities
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/activity-objects/search:
    post:
      operationId: search_activity_objects
      summary: Search activity objects
      description: |-
        The event feed folded by object: one row per person or company holding a fact under the filter, by its latest fact, newest first, with its fact count, fresh count and newest three types. Who gave a signal lately: filter type in the signal types; new since yesterday: fresh.created_at and fresh_objects. filter takes every leaf of search_activities; include person or company. Counts count objects, not facts (page_size 0).

        Contract:
        - MCP tool `search_activity_objects`, registry package `mcp.playtables/activity_objects`, mount `playtables.people`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - activity_objects
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchActivityObjectsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchActivityObjectsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_activity_objects
      x-gs-mcp-mount: playtables.people
      x-gs-entity: activity_objects
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies:
    post:
      operationId: create_company
      summary: Create company
      description: |-
        Manually add ONE company, optionally attaching it to a playtable. The service walks the identity dedup ladder (ln_id > canonical company page URL > domain, team-scoped) before inserting; a name-only company (no identity field) skips dedup and is created directly. A stoplist check runs at insert - a domain/LinkedIn match sets status=stoplisted.

        Duplicates are never a dead-end. Without on_duplicate, a dedup hit returns 409 duplicate_rejected with context {existing_sid, already_in_playtable_sids, matched_identifier_kind}. Retry with on_duplicate:"attach" to union playtable_sid into the existing row's membership (requires playtable_sid), or "skip" to return it untouched - both respond already_exists:true, and item.playtable_sids lists every table the company now lives in. Companies attach, never move (multi-table membership; each member table keeps an independent cell set).

        Omit playtable_sid to create a table-less account (anchor for people.company_sid links). Firmographics (industry, size, HQ, …) are playtable field values, not create fields. NOT for bulk import (create a data source + run) or for adding humans (people tools).

        Contract:
        - MCP tool `create_company`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - companies
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateCompanyRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateCompanyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_company
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/companies/metrics:
    post:
      operationId: get_companies_metrics
      summary: Companies metrics
      description: |-
        Period-bound aggregates over a filtered company scope (reads ES - never for money decisions). aggregated.counts = "now" composition (total, with_linkedin/with_domain, groups by status / playtable_sids / data_source_sid / signals); metrics = added_count, deleted_count, linkedin/domain coverage rates. period {from,to} required, half-open; period column created_at - its filter operators are ignored. group_by → one groups[] entry per axis value (cap 500). Per-table badges ride playtables metrics.

        Contract:
        - MCP tool `get_companies_metrics`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetCompaniesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetCompaniesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_companies_metrics
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/read-linkedin:
    post:
      operationId: read_linkedin_company
      summary: Read LinkedIn company
      description: |-
        Read one LinkedIn company page by slug or link, numeric id, or website domain, for the company card: name, tagline, about, industry, people_count, founded_year, location, website, the axes; nothing written. The corpus answers free; a pool read is comped for a workspace's first three, then 2 credits. found false with reason company_not_resolvable (the domain maps to no page), company_not_found, company_unreadable or pool_unavailable (retry_after). A company row is update_company.

        Contract:
        - MCP tool `read_linkedin_company`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - companies
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReadLinkedinCompanyRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReadLinkedinCompanyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: read_linkedin_company
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/search:
    post:
      operationId: search_companies
      summary: Search companies
      description: |-
        Companies from the Elasticsearch projection: every company tab is this tool with filter playtable_sids {in: [<table>]}. Filter coverage (domain is_null), tags, status, signals; q is free text over name, domain, website and LinkedIn. Firmographics are cell-value view conditions, not entity filters. Includes: field_values (custom columns), people_counts, signals; page_size 0 = counts only, counts.groups.signals per signal. Fresh writes lag ES by seconds: read-your-writes is get_company.

        Contract:
        - MCP tool `search_companies`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - companies
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchCompaniesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchCompaniesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_companies
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/suggest:
    post:
      operationId: suggest_company_filter_values
      summary: Suggest company filter values
      description: |-
        Facet helper for building filters - distinct values + row counts for ONE field within a filter scope (ES aggregation). Only field: tag_sids - returns tag sids with counts; resolve labels via tags search. term narrows values by prefix/infix. Firmographic facets (industry, specialities, employee ranges, HQ, …) are playtable field values - facet over cells, not here; free-text name/domain typeahead = q on search_companies.

        Contract:
        - MCP tool `suggest_company_filter_values`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SuggestCompanyFilterValuesRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuggestCompanyFilterValuesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: suggest_company_filter_values
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/{sid}:
    get:
      operationId: get_company
      summary: Get company
      description: |-
        One company by sid, the account card to read before find-contacts or messaging its people (MySQL, read-your-writes). Includes: people_counts, field_values, last_activities, notes, signals.

        Contract:
        - MCP tool `get_company`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_co_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: The cr_co_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - people_counts
                - field_values
                - last_activities
                - notes
                - signals
                - freshness
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetCompanyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_company
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_company
      summary: Update company
      description: |-
        Partial attribute edit: identity fields, deal_size, tags (full-replace), external_refs. An identity edit that collides with another live account persists and flags the edited row status duplicate, naming the primary in duplicate_of_sid; nothing moves, never a 409. name, logo_url and website are manual observations. Firmographics are field values, not here. status and playtable_sids are service-managed. At least one field, else 422 nothing_to_update.

        Contract:
        - MCP tool `update_company`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: Company sid (cr_co_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: Company sid (cr_co_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateCompanyRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateCompanyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_company
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_company
      summary: Delete company
      description: |-
        Cascade soft-delete of one company from all member tables at once (per-table removal is detach_company_playtable; bulk deletion a playtable run). Soft blocker: queued or running paid cells are 409 delete_blocked; confirm, then pass acknowledge [cancel_cells]. Cells hard-delete by job; notes and activities soft-delete with the row; linked people survive, company_sid dangling (hydrates null) and their own company name shown. No recovery. Repeat answers already_deleted true.

        Contract:
        - MCP tool `delete_company`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_co_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: The cr_co_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - cancel_cells
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteCompanyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_company
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/{sid}/detach:
    post:
      operationId: detach_company_playtable
      summary: Detach company from playtable
      description: |-
        Remove ONE table from the company's membership while keeping the account (other memberships, people links, tags, notes, activities intact) - the "remove row from this table" gesture. The detached table's cells are hard-deleted by job - destructive to that table's cell data. Idempotent: a non-member playtable_sid returns result.detached:false, no changes. Detaching the last table is allowed (empty membership). NOT a delete - delete_company removes the account everywhere.

        Contract:
        - MCP tool `detach_company_playtable`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: Company sid (cr_co_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: Company sid (cr_co_…).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DetachCompanyPlaytableRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DetachCompanyPlaytableResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: detach_company_playtable
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/{sid}/make-primary:
    post:
      operationId: make_company_primary
      summary: Make company primary
      description: |-
        Declare an account flagged duplicate the primary of its group: the flag and the pointer swap, this row goes back to ok, the row it duplicated becomes the duplicate pointing here. Nothing moves (merge_companies is the separate act). Reversible: call it on the other row. A row not flagged answers already_primary true. When NOT: moving the leads onto the real account (merge_companies); asking which is primary (duplicate_of_sid on get_company).

        Contract:
        - MCP tool `make_company_primary`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: The flagged duplicate that is the real account.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: The flagged duplicate that is the real account.
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MakeCompanyPrimaryResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: make_company_primary
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/companies/{sid}/merge:
    post:
      operationId: merge_companies
      summary: Merge companies
      description: |-
        Manual duplicate resolution: move the source company's leads onto the target and union the source's table membership into the target, one transaction. The source row is not deleted: it stays; delete_company removes it when ready. Not gated on the duplicate flag. Re-running moves zero people; merging a row into itself is 422. When NOT: naming the real row without moving anything (make_company_primary); a per-table removal (detach_company_playtable).

        Contract:
        - MCP tool `merge_companies`, registry package `mcp.playtables/companies`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - companies
      parameters:
        - name: sid
          in: path
          required: true
          description: The SOURCE (usually the flagged duplicate) - drained, never deleted.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: The SOURCE (usually the flagged duplicate) - drained, never deleted.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MergeCompaniesRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MergeCompaniesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: merge_companies
      x-gs-mcp-mount: playtables.people
      x-gs-entity: companies
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/credit-ledger-entries/metrics:
    post:
      operationId: get_credit_ledger_entries_metrics
      summary: Credit ledger entries metrics
      description: |-
        Credit spend aggregates - THE credits-usage surface: spent (Σ cost) + paid_calls_count over a REQUIRED period (half-open [from,to) on created_at - created_at filter ops ignored), group_by playtable_field_sid | tool_sid | created_date | playtable_sid. Use for: monthly enrichment cost, spend by field/tool/day/table, what run X cost (filter.run_sid). Local receipts - the gtm-api ledger is authoritative billing. Pre-run price → playtable-runs estimate; balance → gs.service.id; line items → search.

        Contract:
        - MCP tool `get_credit_ledger_entries_metrics`, registry package `mcp.playtables/credit_ledger_entries`, mount `id.billing`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - credit_ledger_entries
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetCreditLedgerEntriesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetCreditLedgerEntriesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_credit_ledger_entries_metrics
      x-gs-mcp-mount: id.billing
      x-gs-entity: credit_ledger_entries
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/credit-ledger-entries/search:
    post:
      operationId: search_credit_ledger_entries
      summary: Search credit ledger entries
      description: |-
        Paid-call receipts - append-only: one row per billable waterfall step (failed paid steps too) with cost, tool, run/step, cell coordinates, spender. Use for: receipts of a run/cell/day/actor, "why was this cell charged twice". Requires a scope: playtable_sid/run_sid/object_sid/playtable_field_sid/created_at.gte/sid.in (else 422). Local mirror - the gtm-api ledger is authoritative billing; receipts hard-purge after 12 months. Spend totals → the metrics tool (counts here = call counts).

        Contract:
        - MCP tool `search_credit_ledger_entries`, registry package `mcp.playtables/credit_ledger_entries`, mount `id.billing`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - credit_ledger_entries
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchCreditLedgerEntriesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchCreditLedgerEntriesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_credit_ledger_entries
      x-gs-mcp-mount: id.billing
      x-gs-entity: credit_ledger_entries
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-source-items/move:
    post:
      operationId: move_data_source_duplicates
      summary: Move data source duplicates
      description: |-
        Move the duplicate people a source found into its table after the fact: the rows the policy left where they were (status duplicate, action skipped) move with their stage, owner and history; every kind of source. sids picks some, absent = every one left in place; counts.groups.already_in_playtable_sid on a search says how many and where. Companies never move and count as left. 409 no_target_playtable when the table is gone.

        Contract:
        - MCP tool `move_data_source_duplicates`, registry package `mcp.playtables/data_source_items`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: mass action: this verb's own request accepts a filter or targets[] set, which the owning service drains.
      tags:
        - data_source_items
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MoveDataSourceDuplicatesRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoveDataSourceDuplicatesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: move_data_source_duplicates
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_source_items
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: true
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-source-items/search:
    post:
      operationId: search_data_source_items
      summary: Search data source items
      description: |-
        Row-level drill-down behind an import funnel: one row per raw record a data source staged - the untouched payload plus its promotion outcome (status, status_reason, created_object_sid, duplicate_action). Scope data_source_sid + status for "why didn't these rows make it"; q searches the payload (requires data_source_sid); sid.eq resolves people.data_source_item_sid provenance; include data_source = the source; counts.groups.status = the funnel. Totals/metrics → data-sources tools.

        Contract:
        - MCP tool `search_data_source_items`, registry package `mcp.playtables/data_source_items`, mount `playtables.sources`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - data_source_items
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchDataSourceItemsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchDataSourceItemsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_data_source_items
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_source_items
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources:
    post:
      operationId: create_data_source
      summary: Create data source
      description: |-
        Create an ingestion source into a table. `type` says who runs it and is required: the same Sales Navigator link is a valid ai_search and a valid sender_search, so a link's shape never decides.

        ai_search: exactly one of url, payload.prompt or payload.filters; the pool runs it for credits, no sender. sender_search: sender_profile_sid plus url, unless payload.surface is my_network or messenger; payload.repeat reruns it. post_engagement: sender_profile_sid plus a post, profile or company page link (preview_post_engagement reads it back first); payload.window, relevance, collect and repeat tune it; every person lands with what they did. find_people: payload.company_sids and/or company_filter, plus a prompt or filters; always people. webhook: payload.records_path; the answer carries ingest_url (the credential: rotate to revoke). csv is refused: upload it, then import_data_source.

        Refusals are 422, the reason in field_errors[field][0].rule: url needs_sender (only a Sales Navigator search runs on the pool: the rest is a sender_search), url post_engagement (a post link in a search kind), link_not_recognized, object_type or payload.target agreement, payload in, payload.collect required, and on sender_profile_sid linkedin_account_missing, sales_nav_required, recruiter_required or recruiter_signed_out. No dedup. When NOT: blocking identifiers (create_stoplist_entry); feeding people into outreach (workflow sources).

        Contract:
        - MCP tool `create_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateDataSourceRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/data-sources/ai-plan:
    post:
      operationId: plan_data_source_filters
      summary: Plan data source filters
      description: |-
        Turn a description of who to find into a wire-ready filter set without creating anything: the step before create_data_source when the user should see or edit what will be searched. Paid: the AI parse costs one credit per call. It reads the words into facets (location, industry, current and past company, school, seniority, job function, company headcount, titles as free text) and the platform pool resolves every id-bearing term; a term with no id lands in result.unresolved, never faked. Facets are ANDed and the values inside one facet ORed; there are no exclusion filters, so describe who to find, never who to leave out. A facet keeps at most 10 values: the first ten stay, the dropped terms are named in result.warnings.

        Hand the answer to create_data_source as is: type and object_type from the result, name = suggested_name, payload = {filters, prompt: <the description>} (find_people adds payload.company_sids). create_data_source with payload.prompt alone plans the same way at its first collect step, so call this only when the plan must be seen first.

        Refusals: 422 on prompt when nothing usable was read (ai_parse_failed or ai_empty_filter: rephrase with roles, places or industries); a busy pool answers 503 service_unavailable (context.reason infrastructure_unavailable or search_in_flight) or 429 rate_limited (pool_rate_limited), each with context.retry_after: wait until then, or create the source with the prompt alone and let its collector plan at the pool's pace.

        Contract:
        - MCP tool `plan_data_source_filters`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanDataSourceFiltersRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanDataSourceFiltersResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: plan_data_source_filters
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/data-sources/filter-typeahead:
    post:
      operationId: suggest_data_source_filter_values
      summary: Suggest data source filter values
      description: |-
        Facet ids for a search term: a value plan_data_source_filters left unresolved, or a filter by hand. Free text (titles, names) has no typeahead: a title goes as {text} in current_titles.

        Contract:
        - MCP tool `suggest_data_source_filter_values`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SuggestDataSourceFilterValuesRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuggestDataSourceFilterValuesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: suggest_data_source_filter_values
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/data-sources/metrics:
    post:
      operationId: get_data_sources_metrics
      summary: Data sources metrics
      description: |-
        The import funnel across data sources: items_collected, promoted, duplicate, stoplisted, disqualified, failed, promotion_rate, last_collected_at over the filtered sources' items in a period (on items.created_at; the filter scopes source rows). group_by status | type | object_type adds groups[] per value: the promotion rate per source type is group_by type. aggregated.counts are source-row counts. One source's live funnel: get_data_source with data_source_items_counts; not the activity feed.

        Contract:
        - MCP tool `get_data_sources_metrics`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetDataSourcesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetDataSourcesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_data_sources_metrics
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources/post-engagement-preview:
    post:
      operationId: preview_post_engagement
      summary: Preview post engagement
      description: |-
        A post, profile or company page link read back before a post_engagement source exists: the post's card and counts, or the person or page with 20 recent posts' dates. Nothing created.

        Contract:
        - MCP tool `preview_post_engagement`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PreviewPostEngagementRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewPostEngagementResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: preview_post_engagement
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/data-sources/search:
    post:
      operationId: search_data_sources
      summary: Search data sources
      description: |-
        The team's ingestion sources, one row per pipeline into a table: ai_search (the pool, for credits), sender_search (a sender profile's account), post_engagement (who engaged with a post or someone's posts), find_people, csv, webhook. Filter by type, status, playtable_sid, sender_profile_sid; q is a LIKE over names; include data_source_items_counts (the funnel, with the duplicates left elsewhere) or indexed_counts (rows the grids show). Rows that failed or duplicated: search_data_source_items.

        Contract:
        - MCP tool `search_data_sources`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - data_sources
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchDataSourcesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchDataSourcesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_data_sources
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources/upload-url:
    post:
      operationId: create_data_source_upload_url
      summary: Create data source upload URL
      description: |-
        The agent's way to upload a CSV, since a file cannot ride JSON: this mints a signed single-use URL and parks the import fields; then PUT the raw file bytes to it as the body (a plain HTTP request, Content-Type text/csv, no bearer), which creates the draft source exactly as upload-csv does and answers it with the header preview; then import_data_source on the draft sid confirms the mapping. Nothing exists until the PUT lands; the link dies in 15 minutes.

        Contract:
        - MCP tool `create_data_source_upload_url`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - data_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateDataSourceUploadUrlRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateDataSourceUploadUrlResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_data_source_upload_url
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources/{sid}:
    get:
      operationId: get_data_source
      summary: Get data source
      description: |-
        One source, the poll after create or import; a webhook's ingest_key and ingest_url are on it. Includes: data_source_items_counts (funnel), indexed_counts (grid rows), csv_preview (a draft's rows).

        Contract:
        - MCP tool `get_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The ds_sc_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: The ds_sc_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - playtable
                - sender_profile
                - data_source_items_counts
                - indexed_counts
                - csv_preview
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_data_source
      summary: Update data source
      description: |-
        Partial edit of a source: rename, pause or resume (status active | paused), the mapping of rows not yet promoted, tags, duplicate policy, gate, or another sender profile for a sender_search or a post_engagement. type, object_type and playtable_sid are immutable. A payload patch names only what its kind lets a caller change; payload.prompt rule plan_built and payload.url rule agreement mean the change is a new source. At least one field, else 422 nothing_to_update.

        Contract:
        - MCP tool `update_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: Data source sid (ds_sc_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: Data source sid (ds_sc_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateDataSourceRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_data_source
      summary: Delete data source
      description: |-
        Destructive cascade soft-delete of a source and its own data_source_items staging rows. Promoted objects survive - people, companies, the target playtable and its columns. One soft blocker: an active source with pending items → 409 delete_blocked, code discard_pending_items (confirm dropping not-yet-promoted rows, retry with acknowledge). No hard blockers. No recovery TTL; repeat → already_deleted:true.

        Contract:
        - MCP tool `delete_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The ds_sc_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: The ds_sc_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - discard_pending_items
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources/{sid}/add-companies:
    post:
      operationId: add_companies_to_data_source
      summary: Add companies to data source
      description: |-
        Append companies to a find_people source: its stored filter walks them too, no second plan. Sids already queued are skipped (result.skipped_existing); a completed, failed or paused source is re-armed and resumes at the first new company, an active one just grows its queue. At most 500 new sids per call and 500 still waiting in all (422 names how many wait); nothing new = added 0, no re-arm. When NOT: a different filter or description is a new source; any other kind is 422.

        Contract:
        - MCP tool `add_companies_to_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The find_people source (ds_sc_) whose stored filter walks the companies; any other kind is 422. One that failed plan_failed carries no plan and plans again on its description.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: The find_people source (ds_sc_) whose stored filter walks the companies; any other kind is 422. One that failed plan_failed carries no plan and plans again on its description.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddCompaniesToDataSourceRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddCompaniesToDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: add_companies_to_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/data-sources/{sid}/import:
    post:
      operationId: import_data_source
      summary: Import data source
      description: |-
        Confirm the column mapping and start parsing a csv source: the only draft to active transition, the agent's entry point after the UI's upload-csv hands over a draft sid. It is the last word on what the rows become (object_type) and on what the import does with them (mode): a draft holds nothing yet, so both override what the upload said.

        The mapping is a column preset, not an ingestion filter: it decides which grid columns the import materializes and nothing else, so it may cover no identity column or be [] entirely; every row is staged whole and the dedup ladder uses whatever identity the record carries. mode=update needs match (the existing-row lookup key and the CSV column carrying it); a row that matches nothing fails match_not_found, update never creates.

        Async: the parser streams the file in 1k-row batches, each row becoming a pending data_source_items row promoted on its own. The async ref rides result.pending (expected_completion_seconds, webhook_events, polling_hint), not a top-level pending[]: poll get_data_source with include data_source_items_counts until status is completed or failed, then report the funnel. Not idempotent: a repeat on the now-active source is 409 invalid_transition, a non-csv source 422 on sid; an exhausted contact or credit allowance is 402 payment_required. When NOT: the search and webhook kinds (born active at create); re-running failed rows (an import playtable run).

        Contract:
        - MCP tool `import_data_source`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The draft source (ds_sc_…) - must be status=draft, type=csv; anything else → 409 invalid_transition or 422.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: The draft source (ds_sc_…) - must be status=draft, type=csv; anything else → 409 invalid_transition or 422.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ImportDataSourceRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportDataSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: import_data_source
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/data-sources/{sid}/rotate-ingest-key:
    post:
      operationId: rotate_data_source_ingest_key
      summary: Rotate data source ingest key
      description: |-
        Mint a fresh ingest key for a webhook source. The old URL answers 404 at once, no grace window: whatever posts to it breaks until it gets result.ingest_url. For a leaked URL; confirm with the user.

        Contract:
        - MCP tool `rotate_data_source_ingest_key`, registry package `mcp.playtables/data_sources`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - data_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The webhook source (ds_sc_) whose URL to replace; any other kind is 422. Every call mints another key.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_sc_
            description: The webhook source (ds_sc_) whose URL to replace; any other kind is 422. Every call mints another key.
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RotateDataSourceIngestKeyResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: rotate_data_source_ingest_key
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: data_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/notes:
    post:
      operationId: create_note
      summary: Create note
      description: |-
        Add a plain-text note to exactly one person or company, or a sticker to a workflow canvas (object_type and object_sid must match, the object live in the team). A sticker explains the workflow to its readers: step_id names the step it sits beside (omit it for the whole workflow). No dedup: every call inserts a row. A person or company note writes a note_left activity; a sticker writes none. Not for structured attributes or message content.

        Contract:
        - MCP tool `create_note`, registry package `mcp.playtables/notes`, mount `playtables.pipeline`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - notes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateNoteRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateNoteResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_note
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: notes
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/notes/search:
    post:
      operationId: search_notes
      summary: Search notes
      description: |-
        Read notes: free-form annotations on people and companies, and the stickers on a workflow canvas (object_type workflow). Scope with filter object_sid for one object's notes or one workflow's stickers (read them before changing a workflow), or search team-wide with filter q (FULLTEXT over body); include person and company to cite names. page_size 0 = counts only; counts.groups.object_type rides every response. Not for system facts (sends, replies): the activities timeline.

        Contract:
        - MCP tool `search_notes`, registry package `mcp.playtables/notes`, mount `playtables.pipeline`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - notes
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchNotesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchNotesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_notes
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: notes
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/notes/{sid}:
    patch:
      operationId: update_note
      summary: Update note
      description: |-
        Replace a note's text (body), or move a sticker beside another step (step_id). Team-scoped: any member may edit, created_by stays the author. Never rewrite a sticker a person wrote unless they asked.

        Contract:
        - MCP tool `update_note`, registry package `mcp.playtables/notes`, mount `playtables.pipeline`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - notes
      parameters:
        - name: sid
          in: path
          required: true
          description: Note sid (cr_nt_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_nt_
            description: Note sid (cr_nt_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateNoteRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateNoteResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_note
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: notes
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    delete:
      operationId: delete_note
      summary: Delete note
      description: |-
        Soft-delete a note, stamping deleted_by. The note_left timeline activity survives as a tombstone (retained: activities). Idempotent - repeat calls return already_deleted.

        Contract:
        - MCP tool `delete_note`, registry package `mcp.playtables/notes`, mount `playtables.pipeline`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - notes
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_nt_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_nt_
            description: The cr_nt_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteNoteResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_note
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: notes
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/people:
    post:
      operationId: create_person
      summary: Create person
      description: |-
        Manually add a person to a playtable (single row; bulk ingestion is a playtable-run of type import). The dedup ladder is team-scoped, two tiers: identity keys (ln_member_id, raw ln_id / sn_id / recruiter_id, emails) and flag keys (ln_nickname, phones).

        An identity-tier hit: without on_duplicate → 409 duplicate_rejected with context { existing_sid, already_in_playtable_sid, matched_identifier_kind }; on_duplicate:"skip" → the existing row, already_exists:true; "move" → re-homed into the target playtable. A flag-tier hit (nickname, phone) without on_duplicate CREATES the row flagged status=duplicate (duplicate_of_sid set); an explicit on_duplicate resolves it the same way as identity.

        No identity field at all → status=no_contact_data (dedup skipped; enrichment can lift it to ok). A stoplist check runs at insert → status=stoplisted on match. A LinkedIn URL is parsed to its identifier axes at the edge; emails lowercase. full_name, avatar_url and company_name are manual observations of the birth (the item's context shows them), never columns.

        When NOT: bulk import / bulk delete / moving batches (playtable-runs), profile content like position or location (playtable field values, not entity columns).

        Contract:
        - MCP tool `create_person`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - people
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePersonRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePersonResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_person
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/people/metrics:
    post:
      operationId: get_people_metrics
      summary: People metrics
      description: |-
        Composition/coverage aggregates over a filtered people scope (ES): email/linkedin/phone coverage rates and aggregated.counts as the scope stands NOW; added_count and deleted_count alone ride the period (created_at operators inside filter are silently ignored). Pass filter.playtable_sid for one table's stats, group_by for distributions (groups[] with counts + metrics per axis value). Messaging funnel metrics (sent/replied) live on activities, not here.

        Contract:
        - MCP tool `get_people_metrics`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - people
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetPeopleMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPeopleMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_people_metrics
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/people/read-linkedin:
    post:
      operationId: read_linkedin_person
      summary: Read LinkedIn person
      description: |-
        Read one LinkedIn profile by its slug or pasted link, for the person's own card: name, photo (avatar_url), headline, the current role and company (its slug or company_ln_id for read_linkedin_company), location, positions, languages, the identity axes; nothing written. The corpus answers free; a pool read is comped for a workspace's first three, then 5 credits. alive false with reason profile_not_found, profile_unreadable or pool_unavailable (retry_after). A person row is update_person.

        Contract:
        - MCP tool `read_linkedin_person`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - people
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReadLinkedinPersonRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReadLinkedinPersonResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: read_linkedin_person
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/people/search:
    post:
      operationId: search_people
      summary: Search people
      description: |-
        People: every table view is this tool with filter playtable_sid. Filter statuses, channel coverage (work_email is_null), tags, named signals [{key}]: clicked_not_replied, accepted_not_replied (accepted our invite, got nothing), not the activity feed. q is free text over name, company, emails, LinkedIn; profile content is cells (filter_ast); include field_values renders them. page_size 0 = counts, counts.groups.signals per signal. Fresh writes lag ES seconds: get_person reads your writes.

        Contract:
        - MCP tool `search_people`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - people
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPeopleRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPeopleResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_people
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/people/suggest:
    post:
      operationId: suggest_person_filter_values
      summary: Suggest person filter values
      description: |-
        Facet helper for building people filters - distinct values + row counts for one field within a filter scope (ES aggregation). field: company_name | tag_sids; term narrows by prefix/infix; typical scope filter = { playtable_sid: { eq } }. tag_sids returns tag sids with counts - resolve names via the tags tools. Feed a picked value into search filter eq/in. Profile facets (position, location, …) are playtable field values - facet via the cell-value tooling, not here.

        Contract:
        - MCP tool `suggest_person_filter_values`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - people
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SuggestPersonFilterValuesRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuggestPersonFilterValuesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: suggest_person_filter_values
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/people/{sid}:
    get:
      operationId: get_person
      summary: Get person
      description: |-
        One person, the person card. Includes: company, field_values, workflow_records, last_activities, notes; engagement and engagement_by_sender for the counters; signals (what they mean now).

        Contract:
        - MCP tool `get_person`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - people
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_pp_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
            description: The cr_pp_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - company
                - field_values
                - workflow_records
                - last_activities
                - notes
                - engagement
                - engagement_by_sender
                - signals
                - freshness
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPersonResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_person
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_person
      summary: Update person
      description: |-
        Partial attribute edit: identity fields, phones, channel statuses, company link, tags, external_refs. An identifier edit that collides with another live row persists and flags the edited row status duplicate, naming the primary in duplicate_of_sid (never a 409; make_person_primary swaps the roles). tag_sids is full-replace. status and playtable_sid are service-managed. Profile content is field values, not here. At least one field, else 422 nothing_to_update.

        Contract:
        - MCP tool `update_person`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - people
      parameters:
        - name: sid
          in: path
          required: true
          description: Person sid (cr_pp_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
            description: Person sid (cr_pp_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePersonRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePersonResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_person
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_person
      summary: Delete person
      description: |-
        Destructive cascade soft-delete of one person from the card (bulk = playtable-run type delete). Call without acknowledge first: 409 delete_blocked lists blockers - hard: non-terminal workflow membership (exit via workflow-records, then retry); soft codes: cancel_tasks (future workflow tasks), cancel_cells (queued/running paid cells). Cascade soft-deletes notes + workflow records; cells hard-deleted by job. No API recovery (recovery_available_until:null). Repeat → already_deleted:true.

        Contract:
        - MCP tool `delete_person`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - people
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_pp_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
            description: The cr_pp_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - cancel_tasks
                - cancel_cells
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePersonResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_person
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/people/{sid}/make-primary:
    post:
      operationId: make_person_primary
      summary: Make person primary
      description: |-
        Declare a row flagged duplicate the primary of its group: the flag and the pointer swap, this row goes back to ok (or no_contact_data), the row it duplicated becomes the duplicate pointing here, every other copy is re-pointed here. Nothing is merged or deleted; reversible: call it on the other row. A row not flagged answers already_primary true. When NOT: removing a copy (delete_person); asking which is primary (duplicate_of_sid on get_person).

        Contract:
        - MCP tool `make_person_primary`, registry package `mcp.playtables/people`, mount `playtables.people`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - people
      parameters:
        - name: sid
          in: path
          required: true
          description: The flagged duplicate that is the real record.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
            description: The flagged duplicate that is the real record.
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MakePersonPrimaryResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: make_person_primary
      x-gs-mcp-mount: playtables.people
      x-gs-entity: people
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages:
    post:
      operationId: create_pipeline_stage
      summary: Create pipeline stage
      description: |-
        Add one CUSTOM stage to the end of a pipeline: type is forced to custom, key stays null (system stages exist only in the seeded default sets) and order is assigned as max+1, so sending any of the three is refused. A name colliding with a live stage of the same (team, object) is a 409 duplicate_rejected carrying existing_sid: no dedup-return, so already_exists is always false. To place it anywhere but the end, follow with update_pipeline_stage(order).

        Contract:
        - MCP tool `create_pipeline_stage`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - pipeline_stages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePipelineStageRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePipelineStageResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_pipeline_stage
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages/metrics:
    post:
      operationId: get_pipeline_stages_metrics
      summary: Pipeline stages metrics
      description: |-
        The funnel for one pipeline: per stage, how many objects sit in it now, plus summed deal_size for object:"company". metrics is keyed by stage sid with a "null" entry for the objects in no stage; an empty stage is absent, not zero, and names come from search_pipeline_stages. No period: point-in-time, not a windowed rate. filter is a PEOPLE or COMPANY filter (the shape search_people / search_companies take), never a stage filter. Reads Elasticsearch: a listing number, never a billing one.

        Contract:
        - MCP tool `get_pipeline_stages_metrics`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - pipeline_stages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetPipelineStagesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPipelineStagesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_pipeline_stages_metrics
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages/reset-derivation:
    post:
      operationId: reset_pipeline_stages_derivation
      summary: Reset company stage derivation
      description: |-
        Company-only: hand the listed companies back to the automatic stage derivation. A company is pinned when someone moves it by hand (pipeline_stage_source manual) and stops following its member people; this clears the pin and re-derives each one in the background, so a stage may change as soon as the job runs. Companies not pinned are re-derived anyway and count in reset_count. Person stages are never pinned or derived.

        Contract:
        - MCP tool `reset_pipeline_stages_derivation`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `action`, response envelope `action`.
        - Flags: mass action: this verb's own request accepts a filter or targets[] set, which the owning service drains.
      tags:
        - pipeline_stages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResetPipelineStagesDerivationRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResetPipelineStagesDerivationResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: reset_pipeline_stages_derivation
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: true
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages/search:
    post:
      operationId: search_pipeline_stages
      summary: Search pipeline stages
      description: |-
        A team's pipeline stages. Pin filter object (person | company). The resolver a stage name goes through before any people or companies filter: name eq or q (LIKE over name) for a label the user said, key eq for a system anchor; category in slices the funnel, key is_null true = the custom stages. page_size 0 returns the count alone. Objects per stage: get_pipeline_stages_metrics; the people or companies of a category: search_people or search_companies with filter pipeline_stage_category.

        Contract:
        - MCP tool `search_pipeline_stages`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - pipeline_stages
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPipelineStagesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPipelineStagesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_pipeline_stages
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages/{sid}:
    patch:
      operationId: update_pipeline_stage
      summary: Update pipeline stage
      description: |-
        Rename, recategorize or reposition ONE stage definition; it never moves people or companies between stages (that is move_pipeline_stage_objects). order is the 1..N position and siblings recontiguate around it, which on a person pipeline also rewrites the forward-only rank the auto-advance compares. A system stage (key != null) takes name and order only: another category is a 422, and object / key are refused everywhere. Rename collision: 409; no field at all: 422 nothing_to_update.

        Contract:
        - MCP tool `update_pipeline_stage`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - pipeline_stages
      parameters:
        - name: sid
          in: path
          required: true
          description: Pipeline stage sid (cr_ps_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ps_
            description: Pipeline stage sid (cr_ps_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePipelineStageRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePipelineStageResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_pipeline_stage
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_pipeline_stage
      summary: Delete pipeline stage
      description: |-
        Soft-delete a CUSTOM stage and hand its members to another one. replace_pipeline_stage_sid is required and must be a live stage of the same object: people and companies are repointed to it in the background (retained), so nothing is orphaned, and counts move within seconds rather than instantly. A system stage (key != null) is refused with 422: the auto-transition engine and the company derivation resolve those by key. Never blocked, idempotent (repeat returns already_deleted:true), no restore.

        Contract:
        - MCP tool `delete_pipeline_stage`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - pipeline_stages
      parameters:
        - name: sid
          in: path
          required: true
          description: The custom stage to remove. A system stage (key != null) is refused with 422 validation_failed.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ps_
            description: The custom stage to remove. A system stage (key != null) is refused with 422 validation_failed.
        - name: replace_pipeline_stage_sid
          in: query
          required: true
          description: "Required. Every member object is repointed here, so nothing is orphaned: a live stage of the SAME object (422 otherwise), and not the stage being deleted (the backend does not reject the sid itself, and members would land on the row that just went away)."
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ps_
            description: "Required. Every member object is repointed here, so nothing is orphaned: a live stage of the SAME object (422 otherwise), and not the stage being deleted (the backend does not reject the sid itself, and members would land on the row that just went away)."
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePipelineStageResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_pipeline_stage
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/pipeline-stages/{sid}/move:
    post:
      operationId: move_pipeline_stage_objects
      summary: Move objects into a pipeline stage
      description: |-
        Assign people or companies into one stage (kanban drag, bulk stage change). Unconditional: it bypasses the forward-only rule, so a lead can go backward. Every sid must match the stage's object (cr_pp_ or cr_co_) or the whole call is 422; resolve the stage first with search_pipeline_stages. 1..1000 sids; objects already there return as skipped_count. Moving a company pins it until reset_pipeline_stages_derivation clears the pin.

        Contract:
        - MCP tool `move_pipeline_stage_objects`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
        - Operation `action`, response envelope `action`.
        - Flags: mass action: this verb's own request accepts a filter or targets[] set, which the owning service drains.
      tags:
        - pipeline_stages
      parameters:
        - name: sid
          in: path
          required: true
          description: The TARGET stage the objects are moved into.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_ps_
            description: The TARGET stage the objects are moved into.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MovePipelineStageObjectsRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MovePipelineStageObjectsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: move_pipeline_stage_objects
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: pipeline_stages
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: true
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/plays:
    post:
      operationId: create_play
      summary: Create play
      description: |-
        Create a play. The usual way: catalog_key alone (plus action.workflow_sid for a people play), which births the playbook's entry on the table as it is, once (a second create answers the existing row); then estimate_play, one sentence with the count and the credits, and run_play or the switch. The other way, a play saved from a view: an audience of one tab (the same filter AST a saved view carries), one action and a cadence. find_people over a company audience: the play owns a find_people source born at the first run; add_to_workflow over a people audience: the play owns a manual source born when the workflow is named (here, or later with update_play). A manual play runs on run_play (the click is the consent); a daily play runs by itself while enabled, and switching it on is the consent: estimate_play first, then say what one run does and what a day may spend (daily_credit_limit) in one sentence, and switch it on only after the yes. Refusals: an action that does not fit the object, a switch or a ceiling where it does not apply, a people play switched on with no workflow (422), an archived workflow (409 conflict), a workflow with no published version (409 invalid_transition), an audience the tab refuses (422 under audience).

        Contract:
        - MCP tool `create_play`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - plays
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlayRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePlayResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_play
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/plays/catalog:
    post:
      operationId: list_play_catalog
      summary: List play catalog
      description: |-
        The playbook of a table: the packaged plays (find people at silent or exhausted accounts, find the decision maker, re-engage, reach the untouched), each with the live count of its audience and the row born from it, if any. For where should we top up, whom should we re-engage: answer from the counts, then propose the entries with a count, one approval card each; create_play with the entry's key and run_play (or the switch) does the rest. A play of the playbook runs as it is.

        Contract:
        - MCP tool `list_play_catalog`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - plays
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ListPlayCatalogRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListPlayCatalogResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: list_play_catalog
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/plays/search:
    post:
      operationId: search_plays
      summary: Search plays
      description: |-
        A table's plays as rows: the playbook's born ones (catalog_key set) and the ones saved from a view's filter (catalog_key null), with the audience, the action, the cadence, the switch and what the last run did (last_run_counts). Scope with filter.playtable_sid; page_size:0 = counts only. For the brief and the packaged moves read list_play_catalog; the signal counts behind it are counts.groups.signals of search_companies and search_people with page_size:0.

        Contract:
        - MCP tool `search_plays`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - plays
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaysRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaysResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_plays
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/plays/{sid}:
    patch:
      operationId: update_play
      summary: Update play
      description: |-
        Rename a play, re-aim its audience, change a find_people play's prompt or cap, pick the workflow of a people play that waits for one (once; fixed after), change the cadence, flip the switch, set the ceiling. enabled true is the consent and makes the play due now (422 on a people play with no workflow yet); enabled false stops the next run and cancels nothing in flight; cadence manual switches it off. The sources are fixed at birth. Nothing changed is 422 nothing_to_update.

        Contract:
        - MCP tool `update_play`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - plays
      parameters:
        - name: sid
          in: path
          required: true
          description: Play sid (pt_pl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_pl_
            description: Play sid (pt_pl_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePlayRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePlayResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_play
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_play
      summary: Delete play
      description: |-
        Soft-delete a play. Its find_people source and manual workflow source stay: a walk in progress finishes, the journeys continue; only the standing audience is gone. Repeat answers already_deleted true.

        Contract:
        - MCP tool `delete_play`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - plays
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_pl_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_pl_
            description: The pt_pl_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePlayResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_play
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/plays/{sid}/estimate:
    post:
      operationId: estimate_play
      summary: Estimate play
      description: |-
        What a run now would do, nothing changed: result.matched (the audience as of now), result.acted (what the action would take within the queue's room and the day's ceiling), result.skipped, result.credits (one per account for find_people, 0 for add_to_workflow). The number for the approval card before run_play or before switching a daily play on. A people play with no workflow yet is 422: pick it with update_play first.

        Contract:
        - MCP tool `estimate_play`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - plays
      parameters:
        - name: sid
          in: path
          required: true
          description: Play sid (pt_pl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_pl_
            description: Play sid (pt_pl_…).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EstimatePlayResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: estimate_play
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/plays/{sid}/run:
    post:
      operationId: run_play
      summary: Run play
      description: |-
        Run the play now: the audience resolved, the action taking what it does not already hold (at most 500 rows, within the queue's room and the day's ceiling). The click is the consent of a manual play: estimate_play first and name the count and the credits in one sentence. Refusals: a people play with no workflow yet (422), a find_people source paused by a structural refusal (409 source_paused), a workflow without its published version (409 invalid_transition), an archived workflow (409).

        Contract:
        - MCP tool `run_play`, registry package `mcp.playtables/plays`, mount `playtables.pipeline`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - plays
      parameters:
        - name: sid
          in: path
          required: true
          description: Play sid (pt_pl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_pl_
            description: Play sid (pt_pl_…).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RunPlayResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: run_play
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: plays
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-field-values/search:
    post:
      operationId: search_playtable_field_values
      summary: Search playtable field values
      description: |-
        Cell-level execution records - per-cell status, cost cache, error and pin state, with a counts block (status / playtable_field_sid breakdowns). Use for: which cells errored for a field, why enrichment failed across rows, error-by-field health (page_size:0 + counts.groups). Requires a scope filter: playtable_sid.eq OR object_sid OR sid.in (422 otherwise). NOT for bulk value reads (people/companies search, include:["field_values"]) or money aggregates (credit-ledger-entries tools).

        Contract:
        - MCP tool `search_playtable_field_values`, registry package `mcp.playtables/playtable_field_values`, mount `playtables.columns`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - playtable_field_values
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaytableFieldValuesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaytableFieldValuesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_playtable_field_values
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_field_values
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-field-values/write:
    post:
      operationId: write_playtable_field_value
      summary: Write playtable field value
      description: |-
        Write a cell by natural key (column sid + row sid), not by cell sid: the way to fill an EMPTY cell, which has no row and no sid until written (update_playtable_field_value needs one). Same semantics as update: the cell finalizes as done (value null = a manual clear), error_msg clears, a formula cell is pinned, the first write over a system value snapshots it for reset. Works on an existing cell too. 404 on another team's column, 422 when the row is outside its table, 409 while the cell runs.

        Contract:
        - MCP tool `write_playtable_field_value`, registry package `mcp.playtables/playtable_field_values`, mount `playtables.columns`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtable_field_values
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WritePlaytableFieldValueRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WritePlaytableFieldValueResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: write_playtable_field_value
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_field_values
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-field-values/{sid}:
    get:
      operationId: get_playtable_field_value
      summary: Get playtable field value
      description: |-
        Read one cell in full - waterfall trace (meta.steps), error_msg, cost, provider. Use with a cell sid from an object's field_values include (that include is trimmed - no trace).

        Contract:
        - MCP tool `get_playtable_field_value`, registry package `mcp.playtables/playtable_field_values`, mount `playtables.columns`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - playtable_field_values
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_vl_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vl_
            description: The pt_vl_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - field
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytableFieldValueResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable_field_value
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_field_values
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_playtable_field_value
      summary: Update playtable field value
      description: |-
        Inline cell edit - overwrite value (the only mutable field) to fix a wrong result. Finalizes the cell as done - value:null included (clears, stays done: the manual pin) - bumps finished_at, clears error_msg; a formula-backed cell gets pinned (is_value_from_formula=false - the cascade skips it until an explicit run recomputes). Dependent formula cells recompute; object doc reindexes; cost/provider_sid/meta remain last-run history. 409 while status=running; editing a queued cell is safe.

        Contract:
        - MCP tool `update_playtable_field_value`, registry package `mcp.playtables/playtable_field_values`, mount `playtables.columns`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtable_field_values
      parameters:
        - name: sid
          in: path
          required: true
          description: Cell (playtable field value) sid (pt_vl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vl_
            description: Cell (playtable field value) sid (pt_vl_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePlaytableFieldValueRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePlaytableFieldValueResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_playtable_field_value
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_field_values
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-field-values/{sid}/reset:
    post:
      operationId: reset_playtable_field_value
      summary: Reset playtable field value
      description: |-
        Undo a manual overwrite: restore the system value the first edit snapshotted (original_value), clear the edited marker, un-pin a formula cell. 409 unless is_overwritten; 409 while the cell runs.

        Contract:
        - MCP tool `reset_playtable_field_value`, registry package `mcp.playtables/playtable_field_values`, mount `playtables.columns`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtable_field_values
      parameters:
        - name: sid
          in: path
          required: true
          description: Cell (playtable field value) sid (pt_vl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vl_
            description: Cell (playtable field value) sid (pt_vl_…).
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResetPlaytableFieldValueResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: reset_playtable_field_value
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_field_values
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/playtable-fields:
    post:
      operationId: create_playtable_field
      summary: Create playtable field
      description: |-
        Add a column to a playtable: the tool that shapes a table. category is derived from the type prefix, never sent.

        Patterns. Find people (a company grid): type action_find_people with payload.prompt saying who to find at each company (1 credit per company searched, a miss free); switch config.auto_run on (its default condition is a company with no people yet) so a company that lands later is searched by itself, and a playtable run searches the companies already there. Add as column: a scalar whose payload.template is one lone variable such as {{record.enrich.company.employees}}; existing rows backfill free, every future run re-derives it; never touch the action field for this. Composed text: a template with {{people.first_name}} or {{company.name}} (catalog attributes) and record.<slug> (a column of this tab), each refused unless it exists. action_waterfall: config.preset_sid (a gtm-api preset) or hand-built payload.steps, never both.

        Formulas and templates form dependency edges; a cycle rolls the save back with 422 and context.cycle_path. Idempotent on (playtable_sid, slug): a duplicate answers already_exists true with the existing row (check item.type). Nothing paid runs on create (a playtable run, estimate first, or auto_run does); a scalar formula backfill is free. At most 100 live columns per object_type: the 101st is 422 (context.limit).

        Contract:
        - MCP tool `create_playtable_field`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlaytableFieldRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePlaytableFieldResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_playtable_field
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtable-fields/estimate-ai-cost:
    post:
      operationId: estimate_playtable_field_ai_cost
      summary: Estimate playtable field AI cost
      description: |-
        What a Use AI column costs a row of this grid before the save, in credits: the draft's prompt rendered on the grid's first rows, read as tokens, priced per token for every model of the catalog, a range per model (the smallest row to the largest with a typical answer) and a ceiling (the largest row with the model's output cap). No writes, no charges. Use it to quote a column or to pick a model; the run charges each row its real price.

        Contract:
        - MCP tool `estimate_playtable_field_ai_cost`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EstimatePlaytableFieldAiCostRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EstimatePlaytableFieldAiCostResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: estimate_playtable_field_ai_cost
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/estimate-backfill:
    post:
      operationId: estimate_playtable_field_backfill
      summary: Estimate playtable field backfill
      description: |-
        How long a formula column's fill over this grid takes before the save, in seconds: the rows the pass walks, the measured rate one worker sustains and whether the drawer should ask the person first (needs_confirm, above five minutes by default). Two counts, no writes; the fill itself is never gated by it, so a plan builds the column and reads the number.

        Contract:
        - MCP tool `estimate_playtable_field_backfill`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EstimatePlaytableFieldBackfillRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EstimatePlaytableFieldBackfillResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: estimate_playtable_field_backfill
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/generate-condition:
    post:
      operationId: generate_playtable_field_condition
      summary: Generate playtable field condition
      description: |-
        Turn a run rule in words into the AST config.run_condition takes, for a draft column of one tab: one llm.generate call (credits_charged says what it cost), the tab's columns and the built-in attributes as its vocabulary, the answer validated like a saved condition. Never a failed request: error_code says why there is no AST (condition_not_expressible, condition_invalid, generation_unparseable, a lane code). Try it with preview_playtable_field_condition, then save it with nl_condition beside it.

        Contract:
        - MCP tool `generate_playtable_field_condition`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GeneratePlaytableFieldConditionRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GeneratePlaytableFieldConditionResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: generate_playtable_field_condition
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/preview-condition:
    post:
      operationId: preview_playtable_field_condition
      summary: Preview playtable field condition
      description: |-
        Dry run of an UNSAVED run condition over up to 100 named rows of one tab: which rows the column would run on, decided by the same evaluator a paid run uses (MySQL, never the index). No writes, no charges. run_condition null = no gate, every row runs; an unknown record.<slug> or a bad atom is 422 here instead of at save. Use it before create_playtable_field or update_playtable_field sets config.run_condition, on rows from search_people or search_companies.

        Contract:
        - MCP tool `preview_playtable_field_condition`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PreviewPlaytableFieldConditionRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewPlaytableFieldConditionResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: preview_playtable_field_condition
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/preview-run:
    post:
      operationId: preview_playtable_field_run
      summary: Preview playtable field run
      description: |-
        Run an unsaved action_ai_research column against ONE row and answer what its cell would hold: before the column exists, or with the edited prompt of one that does (the drawer's per-row Preview). The same gate, model resolution and output coercion as the paid run, so a preview never promises what the run refuses. PRICED AS ONE ROW: the platform's charge comes back in credits_charged; a row the gate skips (will_run false, skip_reason run_condition_not_met or empty_context) costs nothing. Writes nothing: no cell, no run, no ledger receipt. Every call asks the model again with a fresh key, so a repeat may answer differently and is charged again. Read value, reasoning and confidence; error_code names a refusal before any charge (model_not_in_catalog, web_search_not_supported), a failed call, or an answer that could not be coerced to payload.output (the model ran and was paid). Show the user the sample and its cost; the whole column is create_playtable_run after estimate_playtable_run.

        Contract:
        - MCP tool `preview_playtable_field_run`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - playtable_fields
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PreviewPlaytableFieldRunRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewPlaytableFieldRunResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: preview_playtable_field_run
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtable-fields/search:
    post:
      operationId: search_playtable_fields
      summary: Search playtable fields
      description: |-
        Lists a playtable's columns (filter.playtable_sid.eq) or the team-wide field library (omit playtable_sid). Filter by category / type / object_type / exact slug; q is a LIKE match over name. include[] loads playtable, deps / dependents (dependency edges - their only read surface) or playtable_field_values_counts (per-field cell progress). Search always returns a counts block grouped by category / type / object_type; page_size:0 returns counts only.

        Contract:
        - MCP tool `search_playtable_fields`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - playtable_fields
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaytableFieldsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaytableFieldsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_playtable_fields
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/{sid}:
    get:
      operationId: get_playtable_field
      summary: Get playtable field
      description: |-
        Fetch one column definition by sid - the pointer-chase from a cell's playtable_field_sid or a run scope. include[] adds deps / dependents / playtable / per-field cell-progress counts.

        Contract:
        - MCP tool `get_playtable_field`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_fd_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: The pt_fd_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - playtable
                - deps
                - dependents
                - playtable_field_values_counts
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytableFieldResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable_field
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_playtable_field
      summary: Update playtable field
      description: |-
        Partial update of name, type, payload or config; each JSON value is a full replacement, never a deep merge. slug, category and object_type are immutable. Dependency edges are rebuilt and cycle-checked (a cycle is 422). A set or changed scalar formula recomputes the whole column, manually pinned cells included (warn the user when it holds data); action payload or config changes touch only future runs, paid done cells are never re-run by themselves. At least one field.

        Contract:
        - MCP tool `update_playtable_field`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable field sid (pt_fd_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: Playtable field sid (pt_fd_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePlaytableFieldRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePlaytableFieldResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_playtable_field
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_playtable_field
      summary: Delete playtable field
      description: |-
        Cascade soft-delete of a column. DESTRUCTIVE: cell values are hard-purged (recovery_available_until is always null; spend receipts survive in the credit ledger); re-creating a field with the same slug re-binds existing {{record.<slug>}} references. On 409 delete_blocked: hard blocker = an active workflow version references the slug (pause or edit it first); soft = dependent fields (orphan_dependents) and queued/running cells (cancel_pending_cells). Check include=dependents first.

        Contract:
        - MCP tool `delete_playtable_field`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_fd_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: The pt_fd_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: "Soft-blocker resolution codes the user confirmed. orphan_dependents: dependents keep their source text, their next recalc/run errors until edited. cancel_pending_cells: queued cancelled unbilled; running finish, write discarded."
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - orphan_dependents
                - cancel_pending_cells
            description: "Soft-blocker resolution codes the user confirmed. orphan_dependents: dependents keep their source text, their next recalc/run errors until edited. cancel_pending_cells: queued cancelled unbilled; running finish, write discarded."
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePlaytableFieldResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_playtable_field
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/{sid}/backfill:
    post:
      operationId: backfill_playtable_field
      summary: Fill playtable field again
      description: |-
        Fill a formula column again from the first row: its ledger goes back to queued and the table's recompute pass runs; a small table fills inside the request, a big one rides the queue (result.queued false: it was filling already). Free. The way back from a failed fill; a formula column never runs through create_playtable_run, it fills. 422 without a formula.

        Contract:
        - MCP tool `backfill_playtable_field`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: "The column (pt_fd_…): a scalar column with a formula. A column without one is 422 validation_failed; another team's is 403."
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: "The column (pt_fd_…): a scalar column with a formula. A column without one is 422 validation_failed; another team's is 403."
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackfillPlaytableFieldResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: backfill_playtable_field
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/{sid}/cancel-runs:
    post:
      operationId: cancel_playtable_field_runs
      summary: Stop the runs on a playtable field
      description: |-
        Stop everything running on one column: every unfinished run holding it, active and waiting, is cancelled through the runs' cancel, waiting ones first; a run over several columns stops whole. Queued cells go back; cells a worker holds finish and are charged (in_flight_cells_count); no refunds. Call with dry_run:true first and tell the user the numbers. Nothing running: runs []. A formula column fills and has no stop. One run: cancel_playtable_run; the table: cancel_playtable_runs.

        Contract:
        - MCP tool `cancel_playtable_field_runs`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: "The column (pt_fd_…) whose runs stop: an action column with runs on it. A plain or formula column answers an empty result (nothing of it ever runs: a formula column fills, and a fill has no stop); another team's is 403."
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: "The column (pt_fd_…) whose runs stop: an action column with runs on it. A plain or formula column answers an empty result (nothing of it ever runs: a formula column fills, and a fill has no stop); another team's is 403."
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CancelPlaytableFieldRunsRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelPlaytableFieldRunsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: cancel_playtable_field_runs
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-fields/{sid}/estimate-semantic-index:
    post:
      operationId: estimate_semantic_index
      summary: Estimate semantic index cost
      description: |-
        What switching Semantic search on (or to another embed model) would cost ONE existing column, in credits, before the save: the backfill now (cost_expected over cells_to_embed of cells_filled; text already embedded with the same model is free) and one new or edited value later, as a range (cost_per_value_min to cost_per_value_max: a later value is its own call and its length is unknown until it lands). A dry run of the embed job's own sweep priced by the catalog rule, at the platform key every call runs on. No writes, no charges. Surface the numbers to the user before update_playtable_field sets payload.semantic_index.

        Contract:
        - MCP tool `estimate_semantic_index`, registry package `mcp.playtables/playtable_fields`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtable_fields
      parameters:
        - name: sid
          in: path
          required: true
          description: "The column (pt_fd_…): a scalar_text column, or an action_ai_research column with output: text; any other type is 422 validation_failed."
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
            description: "The column (pt_fd_…): a scalar_text column, or an action_ai_research column with output: text; any other type is 422 validation_failed."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EstimateSemanticIndexRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EstimateSemanticIndexResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: estimate_semantic_index
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_fields
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtable-runs:
    post:
      operationId: create_playtable_run
      summary: Create playtable run
      description: |-
        The single entry point for every bulk operation on a playtable. Async: the created row is the progress handle: poll get_playtable_run with include progress every ~5s until progress.state is finished or cancelled.

        type branches the body. enrich is the only paid type (action columns over the scope; a formula column never runs, it fills through backfill_playtable_field): always estimate_playtable_run first, tell the user the cost range and set max_budget to its cost_max (exhaustion auto-cancels, reason budget_exhausted; a cap at cost_expected cancels a row short); params force_rerun re-queues done cells (re-charge consent), params cells not_run | error narrows to those. export writes the scope to CSV (params format csv, a file_url) or an external tool (write_tool_sid). import batch-promotes a data source (params data_source_sid, no scope). bulk runs tag, field, workflow, move and delete edits (params operation).

        scope, required for enrich, export and bulk: one form, object_sids or view_sid/filter; an empty filter is rejected, the scope is snapshotted at create; hand-picked object_sids and exclude_object_sids are capped at 10 000 each (422 scope_too_large). 409 conflict when a field already has an active run (its sid in error.context), 429 at the team concurrency cap; already_exists is always false. When NOT: single-cell fixes (update_playtable_field_value); continuous source syncing (data sources; import here is a one-shot promotion).

        Contract:
        - MCP tool `create_playtable_run`, registry package `mcp.playtables/playtable_runs`, mount `playtables.columns`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - playtable_runs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlaytableRunRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePlaytableRunResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_playtable_run
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_runs
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtable-runs/estimate:
    post:
      operationId: estimate_playtable_run
      summary: Estimate playtable run cost
      description: |-
        Dry-run pricing for an enrich run - THE money-honesty gate (§4.6): call it BEFORE any paid create_playtable_run(type:"enrich") and surface the range to the user. Resolves the scope row count per field (ES run_condition prefilter - approximate by design, the worker re-checks per cell; done cells are skipped unless force_rerun:true = re-charge consent; cells:not_run | error prices only the cells that have not run or only the error ones) and prices each field's materialized waterfall from the cached gtm-api tool registry.

        Returns rows_matched, cost_min (every row succeeds on the cheapest step), cost_max (full waterfall at max prices), cost_expected (registry expected path), priced_at, and a per-field breakdown with per-step price ranges - pass cost_max as max_budget at create (cost_expected is a midpoint, not a cap). No writes, no charges - free to call; free run types (export|import|bulk) have nothing to estimate. Also the answer to "what would it cost to …" - estimate only, no run. A view/filter scope is priced by count (rows_matched = the ES count; rows_to_run per field subtracts the rows already done unless force_rerun, or counts the error rows by id under cells), so any size prices instantly and rows_matched is never a truncated number.

        Contract:
        - MCP tool `estimate_playtable_run`, registry package `mcp.playtables/playtable_runs`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtable_runs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EstimatePlaytableRunRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EstimatePlaytableRunResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: estimate_playtable_run
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_runs
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtable-runs/search:
    post:
      operationId: search_playtable_runs
      summary: Search playtable runs
      description: |-
        Run history and active bulk operations - filter playtable_sid for one table, type (enrich|export|import|bulk), created_by_actor_sid for "my runs", finished_at:{is_null:true} for active; include progress for derived state + job counters; counts = total/active/groups.type; page_size:0 = counts only. Rows hard-purge 90 days after finishing. NOT for per-cell outcomes (playtable-field-values tools) or spend truth (credit-ledger-entries, filter run_sid).

        Contract:
        - MCP tool `search_playtable_runs`, registry package `mcp.playtables/playtable_runs`, mount `playtables.columns`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - playtable_runs
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaytableRunsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaytableRunsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_playtable_runs
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_runs
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-runs/{sid}:
    get:
      operationId: get_playtable_run
      summary: Get playtable run
      description: |-
        Poll one run after create: include progress for derived state, job counters and spent_credits; file_url lands when an export finishes (presigned, 15-min TTL - re-get for a fresh link).

        Contract:
        - MCP tool `get_playtable_run`, registry package `mcp.playtables/playtable_runs`, mount `playtables.columns`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - playtable_runs
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_rn_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_rn_
            description: The pt_rn_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - progress
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytableRunResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable_run
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_runs
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/playtable-runs/{sid}/cancel:
    post:
      operationId: cancel_playtable_run
      summary: Cancel playtable run
      description: |-
        Stop an active run: cancels the Laravel batch (in-flight steps finish their current step, remaining jobs no-op), reverts still-queued cells, stamps finished_at, emits playtable-runs.cancelled (reason=user). Spent credits are NOT refunded - receipts stand; result carries spent_credits so far (may still grow from in-flight steps) and reverted_cells_count. Idempotent on an already-cancelled run (already_cancelled:true); a normally finished run → 409 conflict.

        Contract:
        - MCP tool `cancel_playtable_run`, registry package `mcp.playtables/playtable_runs`, mount `playtables.columns`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtable_runs
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable run sid (pt_rn_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_rn_
            description: Playtable run sid (pt_rn_…).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelPlaytableRunResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: cancel_playtable_run
      x-gs-mcp-mount: playtables.columns
      x-gs-entity: playtable_runs
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-views:
    post:
      operationId: create_playtable_view
      summary: Create playtable view
      description: |-
        Create a saved view (segment / audience) on one tab of one playtable. object_type is fixed forever; columns/sort/filter are optional - an empty view renders the base-attribute catalog. Every field reference in columns, sort or filter leaves must belong to the same playtable + object_type (422). Duplicate (playtable, object_type, name) returns the existing row with already_exists=true. NOT for default views (born with the playtable) or new field definitions (playtable-fields).

        Contract:
        - MCP tool `create_playtable_view`, registry package `mcp.playtables/playtable_views`, mount `playtables.tables`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - playtable_views
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlaytableViewRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePlaytableViewResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_playtable_view
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtable_views
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-views/search:
    post:
      operationId: search_playtable_views
      summary: Search playtable views
      description: |-
        List saved views of a playtable - grid lenses and workflow audiences. Scope with filter.playtable_sid + object_type for one tab; q searches names; include workflow_sources to see which views are live audiences; counts.groups.object_type feeds tab badges. Use it to resolve a view name into a pt_vw_ sid. NOT for listing the objects matching a view - execute the stored definition via people/companies search.

        Contract:
        - MCP tool `search_playtable_views`, registry package `mcp.playtables/playtable_views`, mount `playtables.tables`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - playtable_views
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaytableViewsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaytableViewsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_playtable_views
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtable_views
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtable-views/{sid}:
    get:
      operationId: get_playtable_view
      summary: Get playtable view
      description: |-
        Fetch one view by sid: the stored columns, sort and filter AST behind a bare view_sid from a workflow source or run scope. Include playtable (owner) and workflow_sources (consumers) before edits.

        Contract:
        - MCP tool `get_playtable_view`, registry package `mcp.playtables/playtable_views`, mount `playtables.tables`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - playtable_views
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_vw_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vw_
            description: The pt_vw_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - playtable
                - workflow_sources
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytableViewResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable_view
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtable_views
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_playtable_view
      summary: Update playtable view
      description: |-
        Partially update a view: name, columns, sort, filter - each JSON field is replaced whole. playtable_sid and object_type are immutable (readonly fields are silently rejected); at least one field required (422 nothing_to_update). WARNING: if workflow sources consume this view, a filter change retargets those live audiences from the poller next cycle - read include=workflow_sources first and confirm with the user.

        Contract:
        - MCP tool `update_playtable_view`, registry package `mcp.playtables/playtable_views`, mount `playtables.tables`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtable_views
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable view sid (pt_vw_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vw_
            description: Playtable view sid (pt_vw_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePlaytableViewRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePlaytableViewResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_playtable_view
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtable_views
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_playtable_view
      summary: Delete playtable view
      description: |-
        Soft-delete a saved view. A default view is rejected with 409 conflict - it lives and dies with its playtable. Consuming workflow sources block deletion: sources on ACTIVE workflows are hard blockers (pause/archive the workflow or delete the source first); sources on draft/paused/archived workflows are detached via acknowledge=["detach_workflow_sources"] and reported in cascade.details.

        Contract:
        - MCP tool `delete_playtable_view`, registry package `mcp.playtables/playtable_views`, mount `playtables.tables`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtable_views
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_vw_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_vw_
            description: The pt_vw_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - detach_workflow_sources
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePlaytableViewResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_playtable_view
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtable_views
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtables:
    post:
      operationId: create_playtable
      summary: Create playtable
      description: |-
        Create a table plus its two default views (object_type=company and people, name "Default view", empty columns/sort/filter) in one transaction; the returned row carries both view sids. Idempotent dedup on (team_sid, name): a duplicate returns the existing row with already_exists:true. config.auto_run defaults to false - paid fields do not fire on import until enabled. The usual next step is create_data_source targeting the new sid.

        Contract:
        - MCP tool `create_playtable`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - playtables
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlaytableRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePlaytableResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_playtable
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtables/metrics:
    post:
      operationId: get_playtables_metrics
      summary: Playtables metrics
      description: |-
        Per-table child-object aggregates (reads Elasticsearch - listing discipline; never use for money decisions). Metrics: people_count, companies_count, people_with_linkedin_count are "now" totals; people_added_count, companies_added_count are bounded by the required period (half-open [from,to) over the children's created_at - attach time proxied by creation). filter scopes which TABLES aggregate (default live rows).

        Two grouping modes, mutually exclusive (both set → 422): group_by:"sid" → groups[] with one {key, counts, metrics} entry per playtable (dashboard per-table numbers; cap 500 groups - narrow filter.sid.in); group_by_field_sid:"pt_fd_…" → field_value_groups[]: distribution of the field's object_type rows across the options of one scalar_select field (stage funnel; null key = empty/unset cell). group_by_field_sid requires filter.sid.eq = the field's playtable and a scalar_select field (422 otherwise).

        When NOT: per-status people breakdown inside one table → search_people counts with filter.playtable_sid; listing/editing rows → people / companies tools.

        Contract:
        - MCP tool `get_playtables_metrics`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - playtables
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetPlaytablesMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytablesMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtables_metrics
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtables/search:
    post:
      operationId: search_playtables
      summary: Search playtables
      description: |-
        The team's tables (CRM workspace containers, each with a companies tab and a people tab). Filter by sid or name; q matches name and description; include people_counts and companies_counts for the badges, data_sources_counts and workflows_counts. The first call: resolve a table name the user said into a pt_tb_ sid before any other tables call. page_size 0 = counts only. Not for the rows inside a table (search_people, search_companies).

        Contract:
        - MCP tool `search_playtables`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - playtables
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchPlaytablesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchPlaytablesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_playtables
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtables/workspace-performance:
    post:
      operationId: get_workspace_performance
      summary: Workspace performance
      description: |-
        How the WHOLE workspace is doing, its Dashboard: every table at once. For the window asked for (days ending today, or a from..to range) and the one before it: the flow of its people and of its accounts over eight steps (added, enrolled in a workflow, reached, engaged, replied, positive, meeting, won), each counted once on the day they first got there, so a reply rate is replied over reached and a change is shown against before; where everyone stands today at each step (here: still in progress; left: gone to a nurture, negative or disqualified stage); the same window counts per table (which table brings replies or meetings); the window's people by source kind and the ones reached per channel; the money open today and won in the window; and the people by stage category at the end of each day. Narrow it with playtable_sids (those tables' people and accounts) or sender_profile_sids (the people those sender profiles first touched or enrolled). Use for "how is outreach going", "is the pipeline growing", "which table works best", "how many people did we reach this week", "how did Julia's outreach go this month". One table's own flow, all time: get_playtable_performance.

        Contract:
        - MCP tool `get_workspace_performance`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtables
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetWorkspacePerformanceRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetWorkspacePerformanceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_workspace_performance
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtables/{sid}:
    get:
      operationId: get_playtable
      summary: Get playtable
      description: |-
        One table. include views and fields boots a grid (the container, its saved views, its field schema); the tab counts: data_sources_counts, people_counts, companies_counts, workflows_counts.

        Contract:
        - MCP tool `get_playtable`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_tb_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: The pt_tb_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - views
                - fields
                - data_sources_counts
                - people_counts
                - companies_counts
                - workflows_counts
                - outreach_counts
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytableResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_playtable
      summary: Update playtable
      description: |-
        Rename a table, edit its description, or replace config (full-replace of the Value). name is re-checked against the (team_sid, name) guard - 409 duplicate_rejected if taken. Toggling config.auto_run affects only FUTURE row inserts; already-present rows need an explicit run (playtable-runs). sid, team_sid and the two default-view pointers are read-only (silently rejected). At least one field required, else 422 nothing_to_update.

        Contract:
        - MCP tool `update_playtable`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable sid (pt_tb_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: Playtable sid (pt_tb_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePlaytableRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdatePlaytableResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_playtable
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_playtable
      summary: Delete playtable
      description: |-
        Cascade soft-delete of a table AND everything scoped to it - including the table's PEOPLE (people live in exactly one playtable; no re-home on delete). Companies survive (multi-table membership). DESTRUCTIVE.

        Flow: call without acknowledge first → 409 delete_blocked lists blockers. Hard blockers (resolve via other tools, then retry): active_workflow_records - stop/archive the owning workflows or remove the records; attached_workflow_sources - detach workflow sources reading this table's views or archive those workflows; running_playtable_run - cancel the run; import_in_progress - wait for or cancel the import. Soft blockers (confirm with the user, then pass acknowledge[]): people_present → "delete_people" (N people rows soft-deleted with the table); queued_cells → "cancel_queued_cells" (queued, not-yet-spent cell executions cancelled).

        Cascade: views, fields, field deps, field values, people, data sources + items deleted; queued cells cancelled. No recovery TTL (recovery_available_until: null) - restore is an internal/DB operation only. Idempotent: a repeat call returns already_deleted:true with cascade:null. Finished runs, ledger receipts, finished workflow records/tasks, stoplist entries and tags are retained.

        When NOT: removing people from a table (people-level op), archiving a workflow (workflows), or deleting a single view/field (their own delete tools).

        Contract:
        - MCP tool `delete_playtable`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_tb_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: The pt_tb_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - delete_people
                - cancel_queued_cells
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletePlaytableResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_playtable
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/playtables/{sid}/cancel-runs:
    post:
      operationId: cancel_playtable_runs
      summary: Stop the runs of a playtable
      description: |-
        Stop everything running on one table (Stop all): every unfinished run of it, on every tab, active and waiting, is cancelled through the runs' cancel, waiting ones first. Queued cells go back; cells a worker holds finish and are charged (in_flight_cells_count); no refunds. Call with dry_run:true first and tell the user the numbers. Nothing running: runs []. Formula fills are not runs. One column: cancel_playtable_field_runs; one run: cancel_playtable_run (both on /mcp/playtables/columns).

        Contract:
        - MCP tool `cancel_playtable_runs`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: The table (pt_tb_…) whose runs stop, every tab of it. Another team's is 403.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: The table (pt_tb_…) whose runs stop, every tab of it. Another team's is 403.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CancelPlaytableRunsRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelPlaytableRunsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: cancel_playtable_runs
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtables/{sid}/delete-preview:
    post:
      operationId: preview_playtable_delete
      summary: Preview playtable delete
      description: |-
        The read-only dry run of delete_playtable: every blocker the delete would answer (hard ones to resolve first, soft ones listed unwaived with the resolution codes to pass as acknowledge) and the projected cascade (people, views, fields, deps, cells with the queued ones, sources paused) plus what survives (companies kept). Nothing is locked or written: the counts are advisory, the delete re-checks under its lock. Show the user what dies before asking for the confirm; item is the table.

        Contract:
        - MCP tool `preview_playtable_delete`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable sid (pt_tb_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: Playtable sid (pt_tb_…).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewPlaytableDeleteResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: preview_playtable_delete
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/playtables/{sid}/performance:
    post:
      operationId: get_playtable_performance
      summary: Playtable performance
      description: |-
        How ONE table is doing, its Overview. All time: the flow of its people and of its accounts over seven milestones (in_table, reached, engaged, replied, positive, meeting, won), each with how many got at least that far, who sits at it by current stage (here) and who left from it by exit stage (left); the money on its accounts by deal size (open pipeline, won, lost, the accounts without a size counted); its data sources with how far their people got. A person counts at every milestone up to the furthest the ledger or the stages say they reached (a stage stands for its category's milestone; a nurture, negative or disqualified stage is an exit), so the flow narrows by construction. For the window asked for (days ending today, or a from..to range) and the one before it, day by day in the workspace's zone: people added, reached, replied, turned positive, won, and the deal size won; sum each half and compare. Use for "how is this table doing", "where do people drop out", "how much is in the pipeline", "which source works". What happened to whom: search_activities with filter.playtable_sid.

        Contract:
        - MCP tool `get_playtable_performance`, registry package `mcp.playtables/playtables`, mount `playtables.tables`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - playtables
      parameters:
        - name: sid
          in: path
          required: true
          description: Playtable sid (pt_tb_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: Playtable sid (pt_tb_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetPlaytablePerformanceRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetPlaytablePerformanceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_playtable_performance
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: playtables
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/result-pages/search:
    post:
      operationId: search_result_pages
      summary: Search result pages
      description: |-
        List the team's public result pages: chart pictures people put behind a public link from the Share window of the Dashboard or of a table's Overview. Each says whose it is (owner_sid), of which chart (scope, playtable_sid), what it says (headline, description) and where it answers (public_url). For "what have we shared publicly" or to find a page to take down. Metadata only: the picture is at the page's address.

        Contract:
        - MCP tool `search_result_pages`, registry package `mcp.playtables/result_pages`, mount `playtables.tables`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - result_pages
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchResultPagesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchResultPagesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_result_pages
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: result_pages
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/result-pages/{sid}:
    delete:
      operationId: delete_result_page
      summary: Delete result page
      description: |-
        Take one public result page down: its address and both images answer 404 at once (an edge may serve a copy for up to 5 minutes) and its files are deleted. A post that already shows the picture keeps it, but whoever clicks through finds nothing. Never blocked; idempotent (a repeat answers already_deleted: true). No restore: the next publish of that chart from the Share window mints a new address.

        Contract:
        - MCP tool `delete_result_page`, registry package `mcp.playtables/result_pages`, mount `playtables.tables`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - result_pages
      parameters:
        - name: sid
          in: path
          required: true
          description: The pt_rp_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_rp_
            description: The pt_rp_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteResultPageResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_result_page
      x-gs-mcp-mount: playtables.tables
      x-gs-entity: result_pages
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/sender-profiles/stats:
    post:
      operationId: read_sender_profile_stats
      summary: Sender profile stats
      description: |-
        What up to 200 sender profiles did, one row per sid. Today: what each LinkedIn account did against its caps (each action type with its hold and why) and the emails sent against the mailboxes' daily limits. The period from..to: the ledger's done sends and visits. The load: journeys and tasks by status. An unknown sid is left out. For "who is out of invites today" and "who is held"; identity and health: search_sender_profiles; one profile's outreach day by day: get_sender_profile_performance.

        Contract:
        - MCP tool `read_sender_profile_stats`, registry package `mcp.playtables/sender_profiles`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - sender_profiles
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReadSenderProfileStatsRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReadSenderProfileStatsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: read_sender_profile_stats
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: sender_profiles
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/sender-profiles/{sid}/performance:
    post:
      operationId: get_sender_profile_performance
      summary: Sender profile performance
      description: |-
        How one sender profile's outreach went, day by day in the workspace's timezone: per day the sends by type, the requests accepted, the people who replied, the bounces and the people moved to a positive stage after a reply. The series is 2 x days long, the previous window first, so a rate compares with the period before. Only outreach counts: a person this sender profile reached through a workflow, a reply only after that first touch. The fleet: search_sender_profiles, read_sender_profile_stats.

        Contract:
        - MCP tool `get_sender_profile_performance`, registry package `mcp.playtables/sender_profiles`, mount `playtables.sources`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - sender_profiles
      parameters:
        - name: sid
          in: path
          required: true
          description: "Sender profile sid (ub_sp_…): the unibox sid, the same on the playtables copy."
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_sp_
            description: "Sender profile sid (ub_sp_…): the unibox sid, the same on the playtables copy."
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetSenderProfilePerformanceRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetSenderProfilePerformanceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_sender_profile_performance
      x-gs-mcp-mount: playtables.sources
      x-gs-entity: sender_profiles
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/stoplist-entries:
    post:
      operationId: create_stoplist_entry
      summary: Create stoplist entries
      description: |-
        Block identifiers from all outreach, enforced at import, workflow entry, dispatch and sends. One identifier_type and 1..500 values per call. Values are normalized, in-batch duplicates collapse, listed values return their live row (already_exists true). Atomic: one bad value fails the whole call (field_errors per index) and nothing is written. New rows flip matching people to stoplisted (async). source csv_import marks values from a file.

        Contract:
        - MCP tool `create_stoplist_entry`, registry package `mcp.playtables/stoplist_entries`, mount `playtables.stoplist`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - stoplist_entries
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateStoplistEntryRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateStoplistEntryResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_stoplist_entry
      x-gs-mcp-mount: playtables.stoplist
      x-gs-entity: stoplist_entries
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/stoplist-entries/search:
    post:
      operationId: search_stoplist_entries
      summary: Search stoplist entries
      description: |-
        Read the team do-not-contact registry - entries here block people at import promotion, workflow-source entry and task dispatch, and feed the Messaging send-gate. filter.value.eq answers "is X blocked?" (raw forms fine - normalized before compare); q finds fragments ("acme"); slice by identifier_type / source / data_source_sid; deleted_at.is_null:false audits past un-stoplists; page_size:0 + counts.groups = list composition. NOT for why a person is stoplisted - that state lives on people.

        Contract:
        - MCP tool `search_stoplist_entries`, registry package `mcp.playtables/stoplist_entries`, mount `playtables.stoplist`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - stoplist_entries
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchStoplistEntriesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchStoplistEntriesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_stoplist_entries
      x-gs-mcp-mount: playtables.stoplist
      x-gs-entity: stoplist_entries
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/stoplist-entries/{sid}:
    delete:
      operationId: delete_stoplist_entry
      summary: Delete stoplist entry
      description: |-
        Un-stoplist one identifier: soft delete + deleted_by stamp. Destructive for protection - the value becomes contactable again everywhere. Matching people are rechecked async: status lifts to ok only if no other live entry matches; the Messaging send-gate replica drops the value. Rows are immutable - fixing a wrong value = delete + create; re-blocking later inserts a new row (deleted rows never resurrect). Find the sid via search first.

        Contract:
        - MCP tool `delete_stoplist_entry`, registry package `mcp.playtables/stoplist_entries`, mount `playtables.stoplist`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - stoplist_entries
      parameters:
        - name: sid
          in: path
          required: true
          description: The sl_sl_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^sl_sl_
            description: The sl_sl_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteStoplistEntryResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_stoplist_entry
      x-gs-mcp-mount: playtables.stoplist
      x-gs-entity: stoplist_entries
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/tags:
    post:
      operationId: create_tag
      summary: Create tag
      description: |-
        Ensure a label exists. Case-insensitive (team_sid, name) dedup: a duplicate returns the existing row, already_exists:true, color untouched. Applying tags to objects is a people/companies update.

        Contract:
        - MCP tool `create_tag`, registry package `mcp.playtables/tags`, mount `playtables.pipeline`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - tags
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTagRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateTagResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_tag
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: tags
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/tags/search:
    post:
      operationId: search_tags
      summary: Search tags
      description: |-
        List the team's tag taxonomy - one row per label (name + color); objects reference labels via tag_sids[] sid arrays. q = LIKE over names; name.eq/in resolves exact labels to cr_tg_ sids before building a tag_sids filter on people/companies; sid.in resolves sids back to names (e.g. after people.suggest buckets). page_size:0 = taxonomy size only. Applying/removing tags is a people/companies update, not a tag op; counting tagged objects is people/companies suggest(field:'tag_sids').

        Contract:
        - MCP tool `search_tags`, registry package `mcp.playtables/tags`, mount `playtables.pipeline`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - tags
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchTagsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchTagsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_tags
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: tags
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/tags/{sid}:
    patch:
      operationId: update_tag
      summary: Update tag
      description: |-
        Rename or recolor a label. A case-insensitive collision with another live tag → 409 duplicate_rejected. Objects store sids, so no referencing row changes; color:null resets to the default palette.

        Contract:
        - MCP tool `update_tag`, registry package `mcp.playtables/tags`, mount `playtables.pipeline`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - tags
      parameters:
        - name: sid
          in: path
          required: true
          description: Tag sid (cr_tg_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
            description: Tag sid (cr_tg_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateTagRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateTagResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_tag
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: tags
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    delete:
      operationId: delete_tag
      summary: Delete tag
      description: |-
        Soft-delete a label - never blocked by references. people / companies / data_sources rows survive (retained); TagArraysCleanupJob scrubs the sid from their tag_sids[] arrays asynchronously, so chips may render for a few more seconds (readers skip unknown sids). No restore: re-creating the name mints a new sid. Idempotent - repeat returns already_deleted:true.

        Contract:
        - MCP tool `delete_tag`, registry package `mcp.playtables/tags`, mount `playtables.pipeline`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - tags
      parameters:
        - name: sid
          in: path
          required: true
          description: The cr_tg_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
            description: The cr_tg_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteTagResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_tag
      x-gs-mcp-mount: playtables.pipeline
      x-gs-entity: tags
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-attachments/search:
    post:
      operationId: search_workflow_attachments
      summary: Search workflow attachments
      description: |-
        List the team's uploaded files, the library an email_send step picks from: how a file a person uploaded becomes the wf_at_ sid a step's attachments[] carries. q or name for the label they said, sid.in to check refs already in a step are still live, mime_type / size_bytes to pick between similar files. Sort created_at (default, newest first), name or size_bytes; page_size:0 = the library size. Metadata only: the bytes never ride the wire and there is no download, so a file cannot be read here.

        Contract:
        - MCP tool `search_workflow_attachments`, registry package `mcp.playtables/workflow_attachments`, mount `playtables.workflows`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflow_attachments
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowAttachmentsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowAttachmentsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflow_attachments
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_attachments
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-attachments/upload-url:
    post:
      operationId: create_workflow_attachment_upload_url
      summary: Create workflow attachment upload URL
      description: |-
        The agent's way to add a file to the library, since bytes cannot ride JSON: this mints a signed single-use URL; then PUT the raw file bytes to it as the body (a plain HTTP request with the file's Content-Type, one of result.content_types, no bearer, at most max_bytes), which stores the file exactly as the multipart upload does and answers the wf_at_ row; then name that sid in an email_send step's attachments[]. Nothing exists until the PUT lands; the link dies in 15 minutes.

        Contract:
        - MCP tool `create_workflow_attachment_upload_url`, registry package `mcp.playtables/workflow_attachments`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflow_attachments
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWorkflowAttachmentUploadUrlRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateWorkflowAttachmentUploadUrlResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_workflow_attachment_upload_url
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_attachments
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-attachments/{sid}:
    delete:
      operationId: delete_workflow_attachment
      summary: Delete workflow attachment
      description: |-
        Soft-delete one file from the library. Never blocked, and that is the trap: a published email_send step still naming this sid keeps the ref (retained: workflow_versions) and fails its send with attachment_missing, sending nothing rather than a partial set. There is no reverse index: the steps naming it turn up only in workflow step documents (attachments[]), so republish those first. Idempotent (repeat returns already_deleted:true); no restore through the API, and re-uploading mints a new sid.

        Contract:
        - MCP tool `delete_workflow_attachment`, registry package `mcp.playtables/workflow_attachments`, mount `playtables.workflows`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_attachments
      parameters:
        - name: sid
          in: path
          required: true
          description: The wf_at_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_at_
            description: The wf_at_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteWorkflowAttachmentResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_workflow_attachment
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_attachments
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/metrics:
    post:
      operationId: get_workflow_records_metrics
      summary: Workflow records metrics
      description: |-
        Period-bound enrollment/outcome funnel: entered_count (created_at in the half-open [from,to) window), completed/failed/exited counts + completion_rate + avg_hours_to_complete (finished_at clock, same window). group_by one axis (status | workflow_sid | current_step_id | sender_profile_sid | entered_via_source_sid) adds groups[] with counts + metrics per value; current_step_id grouping requires workflow_sid.eq in filter (422). created_at operators in filter are ignored - period owns the window.

        Contract:
        - MCP tool `get_workflow_records_metrics`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - workflow_records
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetWorkflowRecordsMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetWorkflowRecordsMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_workflow_records_metrics
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/search:
    post:
      operationId: search_workflow_records
      summary: Search workflow records
      description: |-
        People-in-workflow rows. Progress board: filter workflow_sid + status; counts.groups.current_step_id = board columns. Person card: filter people_sid ("which workflows is X in"). Staleness sweep: last_touch_at.lte + sort last_touch_at asc; for failed rows read error_code/error_message. include people hydrates names; workflow_tasks_counts = per-record execution shape. No q - resolve names via people search first. page_size:0 = funnel counts only. Adding people = workflow-sources.

        Contract:
        - MCP tool `search_workflow_records`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflow_records
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowRecordsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowRecordsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflow_records
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/{sid}/exit:
    post:
      operationId: exit_workflow_record
      summary: Exit workflow record
      description: |-
        Removes the person from the workflow: any non-terminal status → exited (terminal), finished_at stamped, open pending/scheduled tasks cancelled in the same transaction (result.cancelled_tasks_count). Already-dispatched send commands are NOT recalled - Messaging's final gate and expires_at bound them. The row survives as membership history; the (workflow, person) UNIQUE keeps re-enrollment blocked. Repeat on exited → already_exited:true; completed/failed* → 409 (already finished).

        Contract:
        - MCP tool `exit_workflow_record`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_records
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow record sid (wf_rc_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_rc_
            description: Workflow record sid (wf_rc_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExitWorkflowRecordRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExitWorkflowRecordResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: exit_workflow_record
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/{sid}/pause:
    post:
      operationId: pause_workflow_record
      summary: Pause workflow record
      description: |-
        Manual hold on one enrollment: active or waiting to paused_manual; the dispatcher skips paused records, so nothing is sent until resume. Open tasks freeze in place. A repeat on paused_manual answers already_paused true. Pausing a paused_on_reply record is 409 invalid_transition (the reply hold is the reply flow's); a row the person gate holds is 409 too, exit is its one verb; terminal is 409. reason (max 512) lands in the event payload only.

        Contract:
        - MCP tool `pause_workflow_record`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflow_records
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow record sid (wf_rc_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_rc_
            description: Workflow record sid (wf_rc_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PauseWorkflowRecordRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PauseWorkflowRecordResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: pause_workflow_record
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/{sid}/restart:
    post:
      operationId: restart_workflow_record
      summary: Restart workflow record from top
      description: |-
        Start one person's journey over: open tasks are cancelled, the version and sender profile pinned again, the step reset, the first task planned now. From any status the person gate does not hold, finished or in flight. Refusals: a row the gate holds is 409 (exit is its verb); a stoplisted or duplicate person 409 conflict; an archived or unpublished workflow 409; a sender profile outside the pool 422. Every call is another restart.

        Contract:
        - MCP tool `restart_workflow_record`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_records
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow record sid (wf_rc_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_rc_
            description: Workflow record sid (wf_rc_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RestartWorkflowRecordRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RestartWorkflowRecordResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: restart_workflow_record
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-records/{sid}/resume:
    post:
      operationId: resume_workflow_record
      summary: Resume workflow record
      description: |-
        Release a paused enrollment: paused_on_reply or paused_manual to active. Resuming from paused_on_reply is the continue-after-reply decision, normally the AI SDR's; this is the human or agent override. A live record not paused answers already_active true; a row the person gate holds (waiting_limit, blocked, paused_blocked) is 409 invalid_transition, the gate decides; terminal is 409. reason (max 512) goes to the event payload only.

        Contract:
        - MCP tool `resume_workflow_record`, registry package `mcp.playtables/workflow_records`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_records
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow record sid (wf_rc_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_rc_
            description: Workflow record sid (wf_rc_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResumeWorkflowRecordRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResumeWorkflowRecordResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: resume_workflow_record
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_records
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-sources:
    post:
      operationId: create_workflow_source
      summary: Create workflow source
      description: |-
        Attach an audience feed to a campaign. Payload is XOR by type: view ⇒ view_sid (live view membership); filter ⇒ filter (inline AST over the team's people); manual ⇒ optional people_sids enrolled synchronously (requires a published version). auto_add:true (view/filter only) enqueues an immediate first sweep - no 10-minute wait. Duplicate (workflow_sid, view_sid) → already_exists:true with the existing row. NOT for importing external data into the CRM (data-sources) - this feeds EXISTING people.

        Contract:
        - MCP tool `create_workflow_source`, registry package `mcp.playtables/workflow_sources`, mount `playtables.workflows`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - workflow_sources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWorkflowSourceRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateWorkflowSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_workflow_source
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_sources
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-sources/search:
    post:
      operationId: search_workflow_sources
      summary: Search workflow sources
      description: |-
        List a workflow's audience feeds with their entry counters - the "why did only 80 of 120 enter" surface (entered_count vs blocked_*_count per row). Scope with filter.workflow_sid; filter.view_sid answers "which workflows feed from view X". include=workflow_records_counts adds each source's downstream status funnel; include=view hydrates the pointed view. page_size:0 = counts only. Per-person entry state / journey position is workflow-records search, not here.

        Contract:
        - MCP tool `search_workflow_sources`, registry package `mcp.playtables/workflow_sources`, mount `playtables.workflows`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflow_sources
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowSourcesRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowSourcesResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflow_sources
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_sources
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-sources/{sid}:
    patch:
      operationId: update_workflow_source
      summary: Update workflow source
      description: |-
        Rename, toggle auto_add, repoint view_sid (type=view) or replace filter (type=filter) - a payload key that does not match the source's immutable type → 422. Takes effect next poll cycle; turning auto_add on enqueues an immediate sweep. Already-enrolled records are never touched - entry is one-way (removal = workflow-records exit). Use {auto_add:false} to stop new entries while journeys keep running (NOT workflows pause - that freezes dispatch). Archived parent → 409 conflict.

        Contract:
        - MCP tool `update_workflow_source`, registry package `mcp.playtables/workflow_sources`, mount `playtables.workflows`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - workflow_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow source sid (wf_sr_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_sr_
            description: Workflow source sid (wf_sr_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateWorkflowSourceRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateWorkflowSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_workflow_source
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_sources
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_workflow_source
      summary: Delete workflow source
      description: |-
        Soft-delete an audience feed. Destructive for the FEED only: the poller stops matching it within one cycle; people already enrolled through it keep their journeys running - removing them is workflow-records exit, never this. No blockers; retained: workflow_records, playtable_views. Repeat call → already_deleted:true. To merely stop new entries but keep the pointer, prefer update {auto_add:false}.

        Contract:
        - MCP tool `delete_workflow_source`, registry package `mcp.playtables/workflow_sources`, mount `playtables.workflows`.
        - Operation `delete`, response envelope `delete_simple`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: The wf_sr_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_sr_
            description: The wf_sr_* sid of the row to delete.
      responses:
        "200":
          description: "`delete_simple` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteWorkflowSourceResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_workflow_source
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_sources
      x-gs-operation: delete
      x-gs-envelope: delete_simple
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-sources/{sid}/add-people:
    post:
      operationId: add_workflow_source_people
      summary: Add people to workflow source
      description: |-
        Add specific people to a workflow through a manual source - THE "add selected to campaign" surface (valid on type=manual sources only; create one first if none exists). Runs the full entry pipeline synchronously per person, reading MySQL (never ES): person exists → not stoplisted (stoplist_entries + people.status) → within active_limit / coworkers_limit (over-cap people WAIT). A NEW person gets a workflow_records row pinned to the published version, sender pinned by rotation_strategy; a person ALREADY in the workflow is RE-ENTERED (existing record reused + reset to the top - deliberate re-run). Requires a published version (422 invalid_transition) and a non-archived workflow (409 conflict).

        All-or-nothing input: any unknown people_sid → 422 relation_not_found and nobody is enrolled - resolve sids via people search first. NOT idempotent for already-enrolled people: each call re-runs them. result = THIS call's counts (entered / re_entered / blocked_stoplisted / blocked_limit / blocked_other) - relay them ("4 entered, 1 re-run, 1 blocked: stoplisted"); item = the source row after the call.

        When NOT: a living audience that keeps growing (create a view/filter source with auto_add:true); removing an enrolled person (workflow-records exit); importing new contacts into the CRM (data-sources).

        Contract:
        - MCP tool `add_workflow_source_people`, registry package `mcp.playtables/workflow_sources`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflow_sources
      parameters:
        - name: sid
          in: path
          required: true
          description: Manual source (wf_sr_…, type=manual) - any other type → 422 validation_failed.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_sr_
            description: Manual source (wf_sr_…, type=manual) - any other type → 422 validation_failed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddWorkflowSourcePeopleRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddWorkflowSourcePeopleResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: add_workflow_source_people
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_sources
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/workflow-tasks/search:
    post:
      operationId: search_workflow_tasks
      summary: Search workflow tasks
      description: |-
        One row per step of one record's journey, the execution ledger, and a play's acts. Person timeline: filter people_sid (open statuses = the plan, terminal = history). Manual queue: type eq manual_task, status eq pending, assignee_user_sid. Needs me: initiator eq play, status eq pending; the acts under one event: trigger_activity_sid. counts.groups is the funnel; page_size 0 = counts only. Not for message bodies (search_messages).

        Contract:
        - MCP tool `search_workflow_tasks`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflow_tasks
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowTasksRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowTasksResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflow_tasks
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-tasks/{sid}:
    patch:
      operationId: update_workflow_task
      summary: Update workflow task
      description: |-
        Edit a planned task before it runs: the rendered text (variables_snapshot, partial: the type's template fields, each within its cap) and/or scheduled_at (a past time = send now). Only status scheduled; pending (edit the inbox task), dispatched or terminal is 409 invalid_transition. Find the task via search (people_sid, status eq scheduled) and read variables_snapshot first. Not for changing the step for everyone: update_workflow draft_steps, then publish.

        Contract:
        - MCP tool `update_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - workflow_tasks
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow task sid (wf_tk_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_tk_
            description: Workflow task sid (wf_tk_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateWorkflowTaskRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateWorkflowTaskResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_workflow_task
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-tasks/{sid}/approve:
    post:
      operationId: approve_workflow_task
      summary: Approve workflow task
      description: |-
        Send a draft a play left waiting for approval (initiator play, status pending, a send-class type or move_to_workflow): a congratulation, a comment, a workflow entry. The task goes scheduled now with the text as edited (variables_snapshot) and leaves through the sender profile's own scheduler and limits. A repeat on a scheduled draft answers already_approved true. A question a play asked is complete_workflow_task; a journey's task is never approved (409). To drop a draft: cancel_workflow_task.

        Contract:
        - MCP tool `approve_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_tasks
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow task sid (wf_tk_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_tk_
            description: Workflow task sid (wf_tk_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApproveWorkflowTaskRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApproveWorkflowTaskResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: approve_workflow_task
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-tasks/{sid}/cancel:
    post:
      operationId: cancel_workflow_task
      summary: Cancel workflow task
      description: |-
        Skip this step and keep the sequence: an open (pending or scheduled) task becomes cancelled and the record advances along the step's compiled next. Linear types only: condition, wait_for_event and dispatched tasks are 409 invalid_transition. A repeat answers already_cancelled true. A whole journey stops with pause_workflow_record or exit. A play's draft or question is skipped here (a question leaves the journey paused), and a failed or expired act (cancelled, its error kept).

        Contract:
        - MCP tool `cancel_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_tasks
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow task sid (wf_tk_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_tk_
            description: Workflow task sid (wf_tk_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CancelWorkflowTaskRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelWorkflowTaskResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: cancel_workflow_task
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-tasks/{sid}/complete:
    post:
      operationId: complete_workflow_task
      summary: Complete workflow task
      description: |-
        Close a manual task (pending to done); the note lands in result.note and the record advances. Any other type or status is 409; a repeat answers already_completed true. A question a play asked is answered with choice: remove ends the journey, keep lets it go on, move ends it and puts the person into workflow_sid, add puts an unenrolled person there. Skipping an automated step is cancel_workflow_task; a play's draft is approve_workflow_task.

        Contract:
        - MCP tool `complete_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflow_tasks
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow task sid (wf_tk_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_tk_
            description: Workflow task sid (wf_tk_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompleteWorkflowTaskRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompleteWorkflowTaskResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: complete_workflow_task
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-tasks/{sid}/retry:
    post:
      operationId: retry_workflow_task
      summary: Retry workflow task
      description: |-
        Run a stopped step again for one person: a failed, expired or skipped_stoplisted task is re-armed (the same row, attempt+1) and the record is back active on that step. The cap of 3 does not apply. A send_unconfirmed failure is asked of gtm-api first; resend_unverified true is a person's word it never arrived. 409 invalid_transition on done, skipped, cancelled or skipped_reply (resume the record), an open task, a record that moved on. Not for a whole journey from the top.

        Contract:
        - MCP tool `retry_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflow_tasks
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow task sid (wf_tk_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_tk_
            description: Workflow task sid (wf_tk_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RetryWorkflowTaskRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RetryWorkflowTaskResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: retry_workflow_task
      x-gs-mcp-mount: playtables.journeys
      x-gs-entity: workflow_tasks
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-versions/search:
    post:
      operationId: search_workflow_versions
      summary: Search workflow versions
      description: |-
        Immutable published snapshots of a workflow's step graph - one row per publish, never edited or deleted. Version history: filter.workflow_sid, sort version desc; items carry the FULL steps JSON - keep page_size small (history rarely exceeds 20). include workflow_records_counts = how many records are pinned to each version and in which statuses (the drift check after a republish). page_size:0 = counts only. To change steps edit the workflow's draft_steps and publish.

        Contract:
        - MCP tool `search_workflow_versions`, registry package `mcp.playtables/workflow_versions`, mount `playtables.workflows`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflow_versions
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowVersionsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowVersionsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflow_versions
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_versions
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflow-versions/{sid}:
    get:
      operationId: get_workflow_version
      summary: Get workflow version
      description: |-
        Resolve a wf_vr_ sid (a record's workflow_version_sid or a workflow's published_version_sid) to its frozen step graph; pair with the record's current_step_id to locate a person inside steps.

        Contract:
        - MCP tool `get_workflow_version`, registry package `mcp.playtables/workflow_versions`, mount `playtables.workflows`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - workflow_versions
      parameters:
        - name: sid
          in: path
          required: true
          description: The wf_vr_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_vr_
            description: The wf_vr_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - workflow
                - workflow_records_counts
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetWorkflowVersionResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_workflow_version
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflow_versions
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
  /api/workflows:
    post:
      operationId: create_workflow
      summary: Create workflow
      description: |-
        Create a draft campaign - nothing runs until publish + resume. Optionally seed draft_steps: OMIT step ids (the server assigns them from step_id_seq and returns the array with ids filled). Configure the sender pool (sender_profile_sids + rotation_strategy), the sending window (schedule; null = any time), on_reply and priority. Dedup on (team_sid, name) → already_exists:true. Audiences attach afterwards via workflow-sources, not here.

        Contract:
        - MCP tool `create_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `create`, response envelope `create`.
        - Flags: none.
      tags:
        - workflows
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWorkflowRequest"
      responses:
        "200":
          description: "`create` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: create_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: create
      x-gs-envelope: create
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflows/metrics:
    post:
      operationId: get_workflows_metrics
      summary: Workflows metrics
      description: |-
        Campaign funnel over the filtered workflows: enrolled_in_period / replied_in_period / completed_in_period count record clocks (enrollment / reply / completion) inside half-open [from,to) - NOT workflows.created_at; active_records_now is point-in-time. aggregated.counts = free workflow-row counts by status. group_by:"status" adds groups[] with counts + metrics per value. Per-step funnel → workflow-records metrics with group_by:current_step_id.

        Contract:
        - MCP tool `get_workflows_metrics`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `metrics`, response envelope `metrics`.
        - Flags: read only.
      tags:
        - workflows
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetWorkflowsMetricsRequest"
      responses:
        "200":
          description: "`metrics` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetWorkflowsMetricsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_workflows_metrics
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: metrics
      x-gs-envelope: metrics
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflows/search:
    post:
      operationId: search_workflows
      summary: Search workflows
      description: |-
        List the team's outreach campaigns - multichannel LinkedIn + email sequence containers. Filter by status; q = LIKE over name + description; include records_counts for the per-campaign enrolled/active funnel, sources for audiences, published_version for the live step graph (heavy - full steps JSON). counts.groups.status rides every response; page_size:0 = status dashboard. Default UI scope excludes archived (client-side). Who is enrolled / stuck where → workflow-records search.

        Contract:
        - MCP tool `search_workflows`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `search`, response envelope `search`.
        - Flags: read only.
      tags:
        - workflows
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchWorkflowsRequest"
      responses:
        "200":
          description: "`search` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWorkflowsResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: search_workflows
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: search
      x-gs-envelope: search
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflows/test-api-call:
    post:
      operationId: test_api_call_workflow
      summary: Test an API call step
      description: |-
        Fire ONE api_call step for ONE real person of the team, for real, and return both halves: result.request = the wire request as it went out (method, URL with the variables rendered and the query appended, headers, body; before the connection's auth was injected) and result.status / http_status / response / error_code / error_message = what the target answered. The step is the draft node verbatim (ids optional, nothing saved); {{ai.<key>}} has no record to read and renders empty (or its fallback). A refusing target is status failed in a 200, never an error envelope; the error envelope is reserved for an incomplete node (422, keyed step.<field>) or an unknown person (404). Throttled 10/min. Use it before publish to see exactly what a journey would send.

        Contract:
        - MCP tool `test_api_call_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflows
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TestApiCallWorkflowRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TestApiCallWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: test_api_call_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/workflows/validate:
    post:
      operationId: validate_workflow
      summary: Validate workflow
      description: |-
        Stateless dry-run of the FULL publish validator over a step document. Two modes, exactly one per call: draft_steps inline (pre-create authoring - ids optional, none assigned, nothing saved) or sid (validate the saved draft in place; item = the workflow row, null in stateless mode). Free and read-only: no writes, no events, no version minted.

        An invalid DOCUMENT is a successful validation: 200 with valid:false + ALL errors at once (never fail-fast) in result.errors keyed steps[id=N].{field} (array position for id-less new steps), each with rule + received + fix hint; result.warnings = non-blocking domain lints; result.preview = deterministic ASCII render of every execution path - paste it to the user instead of narrating the graph. The error envelope is reserved for transport/input failures (malformed request, unknown sid). Checks are IDENTICAL to publish_workflow (see its description): document caps (100 steps incl. nested, depth <= 3, 512 KB), end-last, id rules, duration ranges 1m..365d, plus the sender-pool / schedule / template-variable / when-AST / output_key (ask_ai and api_call, one key space) / api_call rules.

        The canonical authoring loop: validate {draft_steps} → fix by result.errors → repeat (<=3) → create → update iterations (carry ids) → publish once → resume. Exists because every publish of a changed draft mints a version - this is its free dry-run twin; a validate-then-publish loop is never surprised.

        Contract:
        - MCP tool `validate_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: read only.
      tags:
        - workflows
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ValidateWorkflowRequest"
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidateWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: validate_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/workflows/{sid}:
    get:
      operationId: get_workflow
      summary: Get workflow
      description: |-
        Fetch one workflow by sid - the editor-open call. draft_steps rides the item; include published_version to diff draft vs live, records_counts for the header funnel.

        Contract:
        - MCP tool `get_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `get`, response envelope `get`.
        - Flags: read only.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: The wf_wf_* sid of the row to read.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: The wf_wf_* sid of the row to read.
        - name: include[]
          in: query
          required: false
          description: Relations to attach to the row; omit for the bare row.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - published_version
                - sources
                - records_counts
                - step_stats
                - forecast
            description: Relations to attach to the row; omit for the bare row.
      responses:
        "200":
          description: "`get` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: get_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: get
      x-gs-envelope: get
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: trivial
    patch:
      operationId: update_workflow
      summary: Update workflow
      description: |-
        Draft-editing verb (partial update). draft_steps is FULL-REPLACE: send the whole array, CARRY the id of every kept step verbatim, OMIT ids on new steps - the response echoes all ids filled. Config edits (sender pool, schedule, on_reply, rotation_strategy, priority) affect FUTURE decisions only; pinned records keep their sender. status = archive family ONLY (archived / paused / draft); anything involving active → 422 - use pause/resume. Archived rows reject other edits.

        Contract:
        - MCP tool `update_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `update`, response envelope `update`.
        - Flags: none.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow sid (wf_wf_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: Workflow sid (wf_wf_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateWorkflowRequest"
      responses:
        "200":
          description: "`update` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: update_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: update
      x-gs-envelope: update
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
    delete:
      operationId: delete_workflow
      summary: Delete workflow
      description: |-
        Destructive cascade soft-delete of a campaign. Blocked while active - hard blocker workflow_active: pause first. Non-terminal records + their scheduled tasks are a soft blocker: confirm with the user, then retry with acknowledge=["cancel_active_records"] - they flip to cancelled and every record/task row soft-deletes in async batches; sources soft-delete with the row. Versions, people, activities and sender profiles are retained. No recovery TTL. Repeat → already_deleted:true.

        Contract:
        - MCP tool `delete_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `delete`, response envelope `delete_cascade`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: The wf_wf_* sid of the row to delete.
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: The wf_wf_* sid of the row to delete.
        - name: acknowledge[]
          in: query
          required: false
          description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              enum:
                - cancel_active_records
            description: Soft-blocker resolution codes the user confirmed. Closed enum; arbitrary strings → 422.
      responses:
        "200":
          description: "`delete_cascade` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: delete_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: delete
      x-gs-envelope: delete_cascade
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflows/{sid}/pause:
    post:
      operationId: pause_workflow
      summary: Pause workflow
      description: |-
        active → paused. Gate-based - no bulk row mutation: source pollers stop enrolling and the dispatcher holds scheduled tasks at dispatch time (MySQL status check); a task already executing in Messaging finishes normally and its result is ingested. Records keep their status. Idempotent on an already-paused workflow; from draft/archived → 422 invalid_transition. result: records_active_count frozen in place + tasks_scheduled_count held at the gate.

        Contract:
        - MCP tool `pause_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: none.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow to pause; must be status=active (paused is a no-op).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: Workflow to pause; must be status=active (paused is a no-op).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PauseWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: pause_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: false
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
  /api/workflows/{sid}/publish:
    post:
      operationId: publish_workflow
      summary: Publish workflow
      description: |-
        Snapshot draft_steps into a new immutable workflow_versions row (version = max+1) and repoint published_version_sid, one transaction. Status is unchanged: publishing while active hot-swaps the version for new enrollments only, in-flight records stay pinned to theirs. Rejected while archived (409 invalid_transition). A draft identical to the published version mints nothing: result.unchanged true, result.version the live one, no event, no validation; a repeated call is a no-op.

        A changed draft is validated whole first; failures are 422 validation_failed with every error at once in field_errors keyed steps[id=N].{field} (array position for id-less new steps), each with a fix hint; non-blocking lints ride as warnings. Checks: 1..100 steps nested included, depth <= 3, end last in its array, id carry and uniqueness; send steps need a non-empty sender pool; {{...}} variables resolve to known namespaces and {{ai.<key>}} follows a preceding ask_ai on every path; condition when is a valid filter AST; ask_ai and api_call output_key unique and {{api.<key>}} follows an api_call that named its answer; api_call URLs https; durations 1m..365d; required_fields.refs resolve like variables. Field slugs resolve at runtime, not at publish.

        result is the version row (the live one when unchanged), previous_version_sid and unchanged; workflows.published fires only when a version was minted. Free dry run: validate_workflow. Go-live is a separate intent: resume_workflow after.

        Contract:
        - MCP tool `publish_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow whose saved draft to publish. Archived → 409 invalid_transition (unarchive first).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: Workflow whose saved draft to publish. Archived → 409 invalid_transition (unarchive first).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PublishWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: publish_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: complex
  /api/workflows/{sid}/resume:
    post:
      operationId: resume_workflow
      summary: Resume workflow
      description: |-
        draft|paused → active. Requires a published version - 422 invalid_transition otherwise (publish first). Opens the gates: source pollers enroll on the next cycle; held tasks dispatch again respecting sending windows and per-sender limits - overdue tasks are NOT burst-flushed, normal scheduling order applies. Idempotent on an already-active workflow. result: tasks_released_count.

        Contract:
        - MCP tool `resume_workflow`, registry package `mcp.playtables/workflows`, mount `playtables.workflows`.
        - Operation `action`, response envelope `action`.
        - Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.
      tags:
        - workflows
      parameters:
        - name: sid
          in: path
          required: true
          description: Workflow to activate; needs published_version_sid non-null (active is a no-op).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^wf_wf_
            description: Workflow to activate; needs published_version_sid non-null (active is a no-op).
      responses:
        "200":
          description: "`action` success envelope."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResumeWorkflowResponse"
        4XX:
          $ref: "#/components/responses/McpClientError"
        5XX:
          $ref: "#/components/responses/McpServerError"
      x-gs-mcp-tool: resume_workflow
      x-gs-mcp-mount: playtables.workflows
      x-gs-entity: workflows
      x-gs-operation: action
      x-gs-envelope: action
      x-gs-availability: ga
      x-gs-dangerous: true
      x-gs-mass-action: false
      x-gs-step-eligible: false
      x-gs-schedule-required: false
      x-gs-tool-class: typical
components:
  securitySchemes:
    BearerJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Access token issued by gs.service.id. Its `access_identity` claim carries `team_sid`, `actor_sid` and `actor_type`, and that team scope is authoritative.
    TeamSid:
      type: apiKey
      in: header
      name: Team-SID
      description: Team scope for tokens that do not carry one. Ignored when the token already names a team.
  responses:
    McpClientError:
      description: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/McpError"
    McpServerError:
      description: MCP error envelope with `error.code` internal_error or service_unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/McpError"
  schemas:
    ActOnActivityRequest:
      type: object
      description: Request body of `act_on_activity`.
      properties:
        do:
          type: string
          enum:
            - like
            - comment
            - send_message
          description: "like or comment: on a post event only (linkedin_post_published), at that post; send_message: a LinkedIn message to the person of any event."
        sender_profile_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: Who acts; absent = the one a play would pick (play_acts.acts_as of the row).
        text:
          type: string
          nullable: true
          maxLength: 8000
          description: The words of a comment (1250 at most) or a message (8000 at most); required for those two.
        reaction:
          type: string
          nullable: true
          enum:
            - like
            - celebrate
            - support
            - love
            - insightful
            - funny
          description: A Like's kind, one of the network's six; like when absent.
      required:
        - do
    ActOnActivityResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
          required:
            - sid
          description: The WorkflowTaskDomain row the act bore (wf_tk_…, initiator user), or the one already on its way.
        result:
          type: object
          properties:
            already_acting:
              type: boolean
              description: true = the same act was on its way already (a Like another hand put on the post, or the same words pressed twice while the first is being sent); the item is that task, nothing new was created.
          required:
            - already_acting
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    AddCompaniesToDataSourceRequest:
      type: object
      description: Request body of `add_companies_to_data_source`.
      properties:
        company_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
          minItems: 1
          maxItems: 500
          description: Companies to search at (cr_co_…, from the companies grid); duplicates and sids already queued are ignored. Required unless company_filter is given.
        company_filter:
          type: object
          additionalProperties: {}
          description: "An account filter resolved at the call, instead of (or with) company_sids: the search_companies filter object as is (the silent accounts of this table, never a list of sids). Past 500 matches the call is 422 rule max; matches already queued are skipped."
    AddCompaniesToDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            added:
              type: integer
              minimum: 0
              description: Companies appended to the queue.
            skipped_existing:
              type: integer
              minimum: 0
              description: Companies the queue already held (searched or waiting), left where they were.
            skipped_disqualified:
              type: integer
              minimum: 0
              description: "Companies left out because their account sits on the Disqualified stage: not collected again, and never a slot of the 500 cap (founder 2026-10-05; the company read answers the stage)."
            queue_size:
              type: integer
              minimum: 0
              description: payload.company_sids length after the append.
            pending:
              type: integer
              minimum: 0
              description: Companies not searched yet, the new ones included.
          required:
            - added
            - skipped_existing
            - skipped_disqualified
            - queue_size
            - pending
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    AddWorkflowSourcePeopleRequest:
      type: object
      description: Request body of `add_workflow_source_people`.
      properties:
        people_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
          minItems: 1
          maxItems: 500
          description: 1..500 people (cr_pp_…). Any unknown sid → 422 relation_not_found and the WHOLE call is rejected (nothing partial).
        restart:
          type: string
          nullable: true
          enum:
            - from_start
            - from_current
          description: "People ALREADY in the workflow. Omitted: a terminal record restarts from_start, an in-flight one is skipped (skipped_in_flight_count). from_start | from_current also re-run in-flight records (from_current: the pinned step); terminal ones restart anyway."
      required:
        - people_sids
    AddWorkflowSourcePeopleResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Source sid (wf_sr_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              description: "[ro] Parent workflow (wf_wf_…) - see ./workflows.md."
            view_sid:
              type: string
              nullable: true
              description: Audience view (pt_vw_…) - set on type=view only, null otherwise; repointable via update - see ./playtable_views.md.
            name:
              type: string
              nullable: true
              description: Optional label ("Conference batch"), max 255; null = unlabeled.
            type:
              type: string
              enum:
                - view
                - filter
                - manual
                - event
              description: "[ro] view = playtable view membership | filter = inline AST | manual = hand-picked people. Immutable - repoint = delete + create."
            event:
              type: string
              nullable: true
              enum:
                - linkedin_connection_request_accepted
                - linkedin_message_replied
                - linkedin_inmail_replied
                - email_replied
                - email_opened
                - email_link_clicked
                - linkedin_invitation_received
                - linkedin_followed
                - website_visited
                - website_key_page_visited
                - website_form_submitted
              description: "type=event only: the activity type that enrolls a person (required at create for an event source, 422 otherwise); null on the other types."
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Inline audience AST (type=filter only, null otherwise) over the team's people; ES resolves membership, record.<slug> leaves resolve per person's playtable (missing slug ⇒ false).
            auto_add:
              type: boolean
              description: "Poller toggle (view/filter): true = every cycle (~10 min) ES lists current audience members and MySQL decides entry; false = dormant pointer. Always false on manual."
            active_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight (non-terminal) records entered via THIS source; null = unlimited. Reached => new candidates wait (blocked_limit_count).
            coworkers_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight records from THIS source for people of the SAME company; null = unlimited. Reached for a company => that company's candidates wait.
            entered_count:
              type: integer
              minimum: 0
              description: "[ro] Total workflow_records ever inserted via this source - monotonic on ALL types (cache of the entered_via_source_sid count)."
            blocked_stoplisted_count:
              type: integer
              minimum: 0
              description: "[ro] Stoplist entry blocks. view/filter: LIVE backlog gauge, recomputed each poll cycle over current audience members (un-stoplisted people drop out and enter); manual: cumulative per call."
            blocked_duplicate_in_workflow_count:
              type: integer
              minimum: 0
              description: "[ro] Poller-only: candidates skipped as already enrolled in this workflow via ANY source (auto_add never re-enters). view/filter: live gauge per poll cycle; ~0 on manual (add-people re-enters instead)."
            blocked_limit_count:
              type: integer
              minimum: 0
              description: "[ro] Candidates WAITING because active_limit / coworkers_limit is reached this cycle; they enter automatically once a slot frees. view/filter: live gauge; manual: cumulative per call."
            blocked_other_count:
              type: integer
              minimum: 0
              description: "[ro] Blocked as deleted/missing/otherwise ineligible people. view/filter: live gauge per poll cycle; manual: cumulative per call."
            last_evaluated_at:
              type: string
              nullable: true
              description: "[ro] Last poll cycle (view/filter) or last add-people / inline-create batch (manual); ISO 8601 UTC, null = never evaluated."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that attached the feed (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the feed (own verb or workflows.delete cascade); null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete - the poller gates on it).
          required:
            - sid
            - team_sid
            - workflow_sid
            - view_sid
            - name
            - type
            - filter
            - auto_add
            - active_limit
            - coworkers_limit
            - entered_count
            - blocked_stoplisted_count
            - blocked_duplicate_in_workflow_count
            - blocked_limit_count
            - blocked_other_count
            - last_evaluated_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            entered_count:
              type: integer
              minimum: 0
              description: NEW workflow_records inserted by THIS call.
            re_entered_count:
              type: integer
              minimum: 0
              description: People already in the workflow RE-ENTERED THIS call - existing record reused + reset (deliberate re-run - workflow_records.md re-entry policy). A TERMINAL record is always restarted (from_start); an IN-FLIGHT record is restarted only when `restart` is passed.
            skipped_in_flight_count:
              type: integer
              minimum: 0
              description: "SKIPPED THIS call: an IN-FLIGHT (active/waiting/paused*) record was left running because no `restart` mode was passed (founder re-entry model §5). Not a duplicate block - the live journey is untouched."
            blocked_stoplisted_count:
              type: integer
              minimum: 0
              description: "Blocked THIS call: stoplist_entries hit or people.status=stoplisted."
            blocked_limit_count:
              type: integer
              minimum: 0
              description: "WAITED THIS call: active_limit / coworkers_limit reached (not enrolled, re-tried when a slot frees)."
            blocked_other_count:
              type: integer
              minimum: 0
              description: "Blocked THIS call: person deleted or otherwise ineligible."
          required:
            - entered_count
            - re_entered_count
            - skipped_in_flight_count
            - blocked_stoplisted_count
            - blocked_limit_count
            - blocked_other_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ApproveWorkflowTaskRequest:
      type: object
      description: Request body of `approve_workflow_task`.
      properties:
        variables_snapshot:
          type: object
          additionalProperties:
            type: string
          description: "Partial: the text as edited before it goes (message for a congratulation, comment for a post), keyed by the type's template field; absent = as drafted."
    ApproveWorkflowTaskResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              nullable: true
              description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
            workflow_version_sid:
              type: string
              nullable: true
              description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
            workflow_record_sid:
              type: string
              nullable: true
              description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
            people_sid:
              type: string
              description: The person (cr_pp_…), denormalized for the person timeline.
            step_id:
              type: integer
              nullable: true
              description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
            type:
              type: string
              enum:
                - linkedin_send_connection_request
                - linkedin_send_message
                - linkedin_send_inmail
                - linkedin_visit_profile
                - linkedin_endorse_skills
                - linkedin_withdraw_connection_request
                - email_send
                - wait
                - wait_for_event
                - condition
                - api_call
                - ask_ai
                - manual_task
                - linkedin_like_latest_post
                - linkedin_comment_latest_post
                - ab_test
                - move_to_workflow
                - add_tag
                - remove_tag
                - set_field
                - change_sender
                - run_column
              description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
            attempt:
              type: integer
              description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
            status:
              type: string
              enum:
                - pending
                - scheduled
                - dispatched
                - done
                - failed
                - skipped
                - skipped_reply
                - skipped_stoplisted
                - cancelled
                - expired
              description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
            initiator:
              type: string
              enum:
                - workflow_record
                - play
                - user
              description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
            play_sid:
              type: string
              nullable: true
              description: The play that bore the task (pt_pl_…); null on a journey's task.
            trigger_activity_sid:
              type: string
              nullable: true
              description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
            act:
              type: object
              nullable: true
              properties:
                do:
                  type: string
                  enum:
                    - send_message
                    - add_to_workflow
                    - like
                    - comment
                    - ask
                  description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                about:
                  type: string
                  enum:
                    - birthday
                    - work_anniversary
                    - job_change
                    - post
                    - website_visit
                    - event
                  description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                actor_sid:
                  type: string
                  description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                target_workflow_sid:
                  type: string
                  description: add_to_workflow, and a question whose move or add names one.
                post_urn:
                  type: string
                  description: "like, comment: the post the act goes to (an activity URN)."
                reaction:
                  type: string
                  description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                options:
                  type: array
                  items:
                    type: string
                    enum:
                      - remove
                      - keep
                      - move
                      - add
                  description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                suggested:
                  type: string
                  enum:
                    - remove
                    - keep
                    - move
                    - add
                  description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
              required:
                - do
                - about
              description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
            sender_profile_sid:
              type: string
              nullable: true
              description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
            assignee_user_sid:
              type: string
              nullable: true
              description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
            scheduled_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
            timeout_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
            dispatched_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped on scheduled → dispatched.
            expires_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once on any terminal status.
            variables_snapshot:
              type: object
              nullable: true
              additionalProperties:
                type: string
              description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
            result:
              type: object
              nullable: true
              additionalProperties: {}
              description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
            error_code:
              type: string
              nullable: true
              description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
            error_message:
              type: string
              nullable: true
              description: Human detail of the failure (max 1024); null on a skip.
            previous_attempts:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  attempt:
                    type: integer
                    description: The attempt number it was.
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                  error_code:
                    type: string
                    nullable: true
                    description: Its reason token.
                  error_message:
                    type: string
                    nullable: true
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                required:
                  - attempt
                  - status
                  - error_code
                  - error_message
                  - result
                  - dispatched_at
                  - finished_at
              description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
            created_at:
              type: string
              description: ISO 8601 UTC - the planning moment.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - workflow_record_sid
            - people_sid
            - step_id
            - type
            - attempt
            - status
            - initiator
            - play_sid
            - trigger_activity_sid
            - act
            - sender_profile_sid
            - assignee_user_sid
            - scheduled_at
            - timeout_at
            - dispatched_at
            - expires_at
            - finished_at
            - variables_snapshot
            - result
            - error_code
            - error_message
            - previous_attempts
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_approved:
              type: boolean
              description: true = the draft was on its way already (status scheduled); nothing changed.
          required:
            - already_approved
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    BackfillPlaytableFieldResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object grid this field belongs to: people or company rows. Fixed at create."
            name:
              type: string
              description: Display label, freely editable.
            slug:
              type: string
              description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
            category:
              type: string
              enum:
                - scalar
                - widget
                - action
              description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
            type:
              type: string
              enum:
                - scalar_text
                - scalar_number
                - scalar_currency
                - scalar_date
                - scalar_url
                - scalar_checkbox
                - scalar_select
                - scalar_multiselect
                - scalar_image
                - widget_data_source
                - widget_tags
                - widget_active_workflows
                - widget_notes
                - widget_company
                - widget_linkedin_id
                - widget_linkedin_channel
                - widget_work_email
                - widget_personal_email
                - widget_email_channel
                - widget_phones
                - widget_phone_channel
                - widget_last_touch
                - widget_activity
                - widget_deal_size
                - widget_website
                - widget_people_summary
                - widget_ai_sdr
                - action_ai_research
                - action_waterfall
                - action_gtm_tool
                - action_find_people
              description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
            payload:
              anyOf:
                - type: object
                  properties:
                    formula:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                    template:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                    nl_formula:
                      type: string
                      nullable: true
                      maxLength: 2048
                      description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                    currency:
                      type: string
                      nullable: true
                      pattern: ^[A-Z]{3}$
                      description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                    option_colors:
                      type: object
                      nullable: true
                      additionalProperties:
                        type: string
                        pattern: ^#[0-9a-f]{6}$
                      description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                  required:
                    - formula
                    - template
                    - nl_formula
                    - options
                    - currency
                    - option_colors
                - type: object
                  properties: {}
                  additionalProperties: false
                  description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^wf_wf_
                      description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                  required:
                    - workflow_sid
                  additionalProperties: false
                - type: object
                  properties:
                    stats_view:
                      type: string
                      enum:
                        - all
                        - last
                        - select
                      description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                    sender_profile_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^ub_sp_
                      description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                  required:
                    - stats_view
                    - sender_profile_sid
                  additionalProperties: false
                - type: object
                  properties:
                    prompt:
                      type: string
                      minLength: 1
                      maxLength: 8192
                      description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                    model:
                      type: string
                      minLength: 1
                      maxLength: 128
                      description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                    output:
                      type: string
                      enum:
                        - text
                        - number
                        - select
                        - json
                      description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Required (min 1) when output=select; null otherwise.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                    web_search:
                      type: boolean
                      description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                  required:
                    - prompt
                    - model
                    - output
                    - options
                    - output_mapping
                - type: object
                  properties:
                    steps:
                      type: array
                      items:
                        type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                        required:
                          - tool_sid
                          - params
                      maxItems: 10
                      description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                    stop_on_first:
                      type: boolean
                      description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                    verify:
                      type: object
                      nullable: true
                      properties:
                        tool_sid:
                          type: string
                          minLength: 1
                          description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                        params:
                          type: object
                          additionalProperties: {}
                          description: Tool params; string values may be Twig templates over the same variable namespace.
                      required:
                        - tool_sid
                        - params
                      description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                    accept_catch_all:
                      type: boolean
                      description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                  required:
                    - steps
                    - stop_on_first
                    - output_mapping
                - type: object
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: gtm-api tool registry sid (external format); existence + price validated at save.
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                  required:
                    - tool_sid
                    - params
                    - output_mapping
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                    per_company_limit:
                      type: integer
                      minimum: 1
                      maximum: 25
                      description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                    qualify:
                      type: object
                      nullable: true
                      properties:
                        "on":
                          type: boolean
                          description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                        criterion:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 2000
                          description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                      required:
                        - "on"
                        - criterion
                      additionalProperties: false
                      description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
              description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                run_condition:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                nl_condition:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                daily_credit_limit:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
              required:
                - auto_run
                - run_condition
                - nl_condition
                - daily_credit_limit
                - preset_sid
            backfill:
              type: object
              nullable: true
              properties:
                status:
                  type: string
                  enum:
                    - queued
                    - running
                    - done
                    - failed
                scanned:
                  type: integer
                  minimum: 0
                  description: Objects the scan has visited so far.
                total:
                  type: integer
                  nullable: true
                  minimum: 0
                  description: The scan size, known once the job starts (null while queued).
                queued_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the column started owing its backfill."
                started_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the job took it."
                finished_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when it ended, done or failed."
                error:
                  type: string
                  nullable: true
                  description: A reason token (backfill_failed) on failed, never an exception message.
              required:
                - status
                - scanned
                - total
                - queued_at
                - started_at
                - finished_at
                - error
              description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - slug
            - category
            - type
            - payload
            - config
            - backfill
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            queued:
              type: boolean
              description: "true: this call owed the fill (item.backfill reads queued, or done when a small table filled inside the request). false: the column was filling already, nothing moved."
          required:
            - queued
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CancelPlaytableFieldRunsRequest:
      type: object
      description: Request body of `cancel_playtable_field_runs`.
      properties:
        dry_run:
          type: boolean
          description: "true: answer the counts (the runs, the queued cells that would go back, the cells still running that finish and are charged) and cancel nothing. Call it first and tell the user the numbers; then call without it."
    CancelPlaytableFieldRunsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object grid this field belongs to: people or company rows. Fixed at create."
            name:
              type: string
              description: Display label, freely editable.
            slug:
              type: string
              description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
            category:
              type: string
              enum:
                - scalar
                - widget
                - action
              description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
            type:
              type: string
              enum:
                - scalar_text
                - scalar_number
                - scalar_currency
                - scalar_date
                - scalar_url
                - scalar_checkbox
                - scalar_select
                - scalar_multiselect
                - scalar_image
                - widget_data_source
                - widget_tags
                - widget_active_workflows
                - widget_notes
                - widget_company
                - widget_linkedin_id
                - widget_linkedin_channel
                - widget_work_email
                - widget_personal_email
                - widget_email_channel
                - widget_phones
                - widget_phone_channel
                - widget_last_touch
                - widget_activity
                - widget_deal_size
                - widget_website
                - widget_people_summary
                - widget_ai_sdr
                - action_ai_research
                - action_waterfall
                - action_gtm_tool
                - action_find_people
              description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
            payload:
              anyOf:
                - type: object
                  properties:
                    formula:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                    template:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                    nl_formula:
                      type: string
                      nullable: true
                      maxLength: 2048
                      description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                    currency:
                      type: string
                      nullable: true
                      pattern: ^[A-Z]{3}$
                      description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                    option_colors:
                      type: object
                      nullable: true
                      additionalProperties:
                        type: string
                        pattern: ^#[0-9a-f]{6}$
                      description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                  required:
                    - formula
                    - template
                    - nl_formula
                    - options
                    - currency
                    - option_colors
                - type: object
                  properties: {}
                  additionalProperties: false
                  description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^wf_wf_
                      description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                  required:
                    - workflow_sid
                  additionalProperties: false
                - type: object
                  properties:
                    stats_view:
                      type: string
                      enum:
                        - all
                        - last
                        - select
                      description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                    sender_profile_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^ub_sp_
                      description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                  required:
                    - stats_view
                    - sender_profile_sid
                  additionalProperties: false
                - type: object
                  properties:
                    prompt:
                      type: string
                      minLength: 1
                      maxLength: 8192
                      description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                    model:
                      type: string
                      minLength: 1
                      maxLength: 128
                      description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                    output:
                      type: string
                      enum:
                        - text
                        - number
                        - select
                        - json
                      description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Required (min 1) when output=select; null otherwise.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                    web_search:
                      type: boolean
                      description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                  required:
                    - prompt
                    - model
                    - output
                    - options
                    - output_mapping
                - type: object
                  properties:
                    steps:
                      type: array
                      items:
                        type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                        required:
                          - tool_sid
                          - params
                      maxItems: 10
                      description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                    stop_on_first:
                      type: boolean
                      description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                    verify:
                      type: object
                      nullable: true
                      properties:
                        tool_sid:
                          type: string
                          minLength: 1
                          description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                        params:
                          type: object
                          additionalProperties: {}
                          description: Tool params; string values may be Twig templates over the same variable namespace.
                      required:
                        - tool_sid
                        - params
                      description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                    accept_catch_all:
                      type: boolean
                      description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                  required:
                    - steps
                    - stop_on_first
                    - output_mapping
                - type: object
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: gtm-api tool registry sid (external format); existence + price validated at save.
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                  required:
                    - tool_sid
                    - params
                    - output_mapping
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                    per_company_limit:
                      type: integer
                      minimum: 1
                      maximum: 25
                      description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                    qualify:
                      type: object
                      nullable: true
                      properties:
                        "on":
                          type: boolean
                          description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                        criterion:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 2000
                          description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                      required:
                        - "on"
                        - criterion
                      additionalProperties: false
                      description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
              description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                run_condition:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                nl_condition:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                daily_credit_limit:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
              required:
                - auto_run
                - run_condition
                - nl_condition
                - daily_credit_limit
                - preset_sid
            backfill:
              type: object
              nullable: true
              properties:
                status:
                  type: string
                  enum:
                    - queued
                    - running
                    - done
                    - failed
                scanned:
                  type: integer
                  minimum: 0
                  description: Objects the scan has visited so far.
                total:
                  type: integer
                  nullable: true
                  minimum: 0
                  description: The scan size, known once the job starts (null while queued).
                queued_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the column started owing its backfill."
                started_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the job took it."
                finished_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when it ended, done or failed."
                error:
                  type: string
                  nullable: true
                  description: A reason token (backfill_failed) on failed, never an exception message.
              required:
                - status
                - scanned
                - total
                - queued_at
                - started_at
                - finished_at
                - error
              description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - slug
            - category
            - type
            - payload
            - config
            - backfill
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            dry_run:
              type: boolean
              description: "true: the counts below are what a stop WOULD do; nothing was cancelled."
            runs:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rn_
                    description: Playtable run sid (pt_rn_…).
                  waiting:
                    type: boolean
                    description: "true: the run held no batch yet (it waited behind another run on its field)."
                  reverted_cells_count:
                    type: integer
                    minimum: 0
                    description: "Its queued cells sent back (on a dry run: the ones that would be)."
                  in_flight_cells_count:
                    type: integer
                    minimum: 0
                    description: "Its cells a worker holds right now: they finish and are charged either way."
                required:
                  - sid
                  - waiting
                  - reverted_cells_count
                  - in_flight_cells_count
              description: "The unfinished runs found, in the order they were stopped: the waiting ones first, then the dispatched ones."
            cancelled_count:
              type: integer
              minimum: 0
              description: Runs this call cancelled (0 on a dry run; a run that ended on its own meanwhile is not counted).
            reverted_cells_count:
              type: integer
              minimum: 0
              description: Queued cells sent back, summed over the runs (no prior value → empty, a prior value → done).
            in_flight_cells_count:
              type: integer
              minimum: 0
              description: "Cells still running, summed over the runs: they finish and are charged. Say so to the user before the stop."
            spent_credits:
              type: number
              description: The runs' spend so far, summed; the in-flight cells may still add to it (the ledger is truth).
          required:
            - dry_run
            - runs
            - cancelled_count
            - reverted_cells_count
            - in_flight_cells_count
            - spent_credits
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CancelPlaytableRunResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            type:
              type: string
              enum:
                - enrich
                - export
                - import
                - bulk
            field_sids:
              type: array
              nullable: true
              items:
                type: string
            scope:
              type: object
              nullable: true
              properties:
                object_sids:
                  type: array
                  nullable: true
                  items:
                    type: string
                view_sid:
                  type: string
                  nullable: true
                filter:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: "Filter AST: and/or/not/any nodes (depth <= 5, root counts) over {field, op} leaves; op = >=1 of the §4.18 atoms; atoms AND."
              required:
                - object_sids
                - view_sid
                - filter
            params_snapshot:
              type: object
              nullable: true
              additionalProperties: {}
            max_budget:
              type: number
              nullable: true
            estimated_cost:
              type: number
              nullable: true
            file_url:
              type: string
              nullable: true
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            finished_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - type
            - field_sids
            - scope
            - params_snapshot
            - max_budget
            - estimated_cost
            - file_url
            - created_by
            - created_at
            - finished_at
        result:
          type: object
          properties:
            already_cancelled:
              type: boolean
              description: true = idempotent no-op (the run was already cancelled).
            reverted_cells_count:
              type: integer
              minimum: 0
              description: Still-queued cells flipped back (no prior value → empty, prior value retained → done). Bulk counters per §4.12a - rows not embedded.
            spent_credits:
              type: number
              description: Σ ledger by run_sid at cancel time; the final figure may still grow from in-flight steps.
          required:
            - already_cancelled
            - reverted_cells_count
            - spent_credits
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CancelPlaytableRunsRequest:
      type: object
      description: Request body of `cancel_playtable_runs`.
      properties:
        dry_run:
          type: boolean
          description: "true: answer the counts (the runs, the queued cells that would go back, the cells still running that finish and are charged) and cancel nothing. Call it first and tell the user the numbers; then call without it."
    CancelPlaytableRunsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            company_default_view_sid:
              type: string
              description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
            people_default_view_sid:
              type: string
              description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
              required:
                - auto_run
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - agent_sid
            - company_default_view_sid
            - people_default_view_sid
            - config
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            dry_run:
              type: boolean
              description: "true: the counts below are what a stop WOULD do; nothing was cancelled."
            runs:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rn_
                    description: Playtable run sid (pt_rn_…).
                  waiting:
                    type: boolean
                    description: "true: the run held no batch yet (it waited behind another run on its field)."
                  reverted_cells_count:
                    type: integer
                    minimum: 0
                    description: "Its queued cells sent back (on a dry run: the ones that would be)."
                  in_flight_cells_count:
                    type: integer
                    minimum: 0
                    description: "Its cells a worker holds right now: they finish and are charged either way."
                required:
                  - sid
                  - waiting
                  - reverted_cells_count
                  - in_flight_cells_count
              description: "The unfinished runs found, in the order they were stopped: the waiting ones first, then the dispatched ones."
            cancelled_count:
              type: integer
              minimum: 0
              description: Runs this call cancelled (0 on a dry run; a run that ended on its own meanwhile is not counted).
            reverted_cells_count:
              type: integer
              minimum: 0
              description: Queued cells sent back, summed over the runs (no prior value → empty, a prior value → done).
            in_flight_cells_count:
              type: integer
              minimum: 0
              description: "Cells still running, summed over the runs: they finish and are charged. Say so to the user before the stop."
            spent_credits:
              type: number
              description: The runs' spend so far, summed; the in-flight cells may still add to it (the ledger is truth).
          required:
            - dry_run
            - runs
            - cancelled_count
            - reverted_cells_count
            - in_flight_cells_count
            - spent_credits
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CancelWorkflowTaskRequest:
      type: object
      description: Request body of `cancel_workflow_task`.
      properties:
        reason:
          type: string
          maxLength: 512
          description: Why the step is skipped - stored in the workflow-tasks.finished event payload only (not on the row).
    CancelWorkflowTaskResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              nullable: true
              description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
            workflow_version_sid:
              type: string
              nullable: true
              description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
            workflow_record_sid:
              type: string
              nullable: true
              description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
            people_sid:
              type: string
              description: The person (cr_pp_…), denormalized for the person timeline.
            step_id:
              type: integer
              nullable: true
              description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
            type:
              type: string
              enum:
                - linkedin_send_connection_request
                - linkedin_send_message
                - linkedin_send_inmail
                - linkedin_visit_profile
                - linkedin_endorse_skills
                - linkedin_withdraw_connection_request
                - email_send
                - wait
                - wait_for_event
                - condition
                - api_call
                - ask_ai
                - manual_task
                - linkedin_like_latest_post
                - linkedin_comment_latest_post
                - ab_test
                - move_to_workflow
                - add_tag
                - remove_tag
                - set_field
                - change_sender
                - run_column
              description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
            attempt:
              type: integer
              description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
            status:
              type: string
              enum:
                - pending
                - scheduled
                - dispatched
                - done
                - failed
                - skipped
                - skipped_reply
                - skipped_stoplisted
                - cancelled
                - expired
              description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
            initiator:
              type: string
              enum:
                - workflow_record
                - play
                - user
              description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
            play_sid:
              type: string
              nullable: true
              description: The play that bore the task (pt_pl_…); null on a journey's task.
            trigger_activity_sid:
              type: string
              nullable: true
              description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
            act:
              type: object
              nullable: true
              properties:
                do:
                  type: string
                  enum:
                    - send_message
                    - add_to_workflow
                    - like
                    - comment
                    - ask
                  description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                about:
                  type: string
                  enum:
                    - birthday
                    - work_anniversary
                    - job_change
                    - post
                    - website_visit
                    - event
                  description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                actor_sid:
                  type: string
                  description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                target_workflow_sid:
                  type: string
                  description: add_to_workflow, and a question whose move or add names one.
                post_urn:
                  type: string
                  description: "like, comment: the post the act goes to (an activity URN)."
                reaction:
                  type: string
                  description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                options:
                  type: array
                  items:
                    type: string
                    enum:
                      - remove
                      - keep
                      - move
                      - add
                  description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                suggested:
                  type: string
                  enum:
                    - remove
                    - keep
                    - move
                    - add
                  description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
              required:
                - do
                - about
              description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
            sender_profile_sid:
              type: string
              nullable: true
              description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
            assignee_user_sid:
              type: string
              nullable: true
              description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
            scheduled_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
            timeout_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
            dispatched_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped on scheduled → dispatched.
            expires_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once on any terminal status.
            variables_snapshot:
              type: object
              nullable: true
              additionalProperties:
                type: string
              description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
            result:
              type: object
              nullable: true
              additionalProperties: {}
              description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
            error_code:
              type: string
              nullable: true
              description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
            error_message:
              type: string
              nullable: true
              description: Human detail of the failure (max 1024); null on a skip.
            previous_attempts:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  attempt:
                    type: integer
                    description: The attempt number it was.
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                  error_code:
                    type: string
                    nullable: true
                    description: Its reason token.
                  error_message:
                    type: string
                    nullable: true
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                required:
                  - attempt
                  - status
                  - error_code
                  - error_message
                  - result
                  - dispatched_at
                  - finished_at
              description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
            created_at:
              type: string
              description: ISO 8601 UTC - the planning moment.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - workflow_record_sid
            - people_sid
            - step_id
            - type
            - attempt
            - status
            - initiator
            - play_sid
            - trigger_activity_sid
            - act
            - sender_profile_sid
            - assignee_user_sid
            - scheduled_at
            - timeout_at
            - dispatched_at
            - expires_at
            - finished_at
            - variables_snapshot
            - result
            - error_code
            - error_message
            - previous_attempts
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_cancelled:
              type: boolean
              description: true = idempotent repeat (the task was already cancelled).
            updated_workflow_record:
              type: object
              nullable: true
              additionalProperties: {}
              description: "The owning record AFTER the advance past the skipped step (WorkflowRecordDomain - entities/workflow_records.md). A play's draft or question skipped: the journey as the play left it (a paused one stays paused), or null when the task has none."
          required:
            - already_cancelled
            - updated_workflow_record
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CompleteWorkflowTaskRequest:
      type: object
      description: Request body of `complete_workflow_task`.
      properties:
        note:
          type: string
          maxLength: 2000
          description: Outcome note - stored in result.note and in the manual_task_completed activity payload.
        choice:
          type: string
          enum:
            - remove
            - keep
            - move
            - add
          description: "A play's question (act.do = ask): one of act.options. remove = the journey ends; keep = it goes on; move = it ends and the person enters workflow_sid (default: the act's target); add = a person in no journey enters workflow_sid. Required on a question."
        workflow_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^wf_wf_
          description: The workflow a move or an add puts the person into, when the act names none.
    CompleteWorkflowTaskResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              nullable: true
              description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
            workflow_version_sid:
              type: string
              nullable: true
              description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
            workflow_record_sid:
              type: string
              nullable: true
              description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
            people_sid:
              type: string
              description: The person (cr_pp_…), denormalized for the person timeline.
            step_id:
              type: integer
              nullable: true
              description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
            type:
              type: string
              enum:
                - linkedin_send_connection_request
                - linkedin_send_message
                - linkedin_send_inmail
                - linkedin_visit_profile
                - linkedin_endorse_skills
                - linkedin_withdraw_connection_request
                - email_send
                - wait
                - wait_for_event
                - condition
                - api_call
                - ask_ai
                - manual_task
                - linkedin_like_latest_post
                - linkedin_comment_latest_post
                - ab_test
                - move_to_workflow
                - add_tag
                - remove_tag
                - set_field
                - change_sender
                - run_column
              description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
            attempt:
              type: integer
              description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
            status:
              type: string
              enum:
                - pending
                - scheduled
                - dispatched
                - done
                - failed
                - skipped
                - skipped_reply
                - skipped_stoplisted
                - cancelled
                - expired
              description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
            initiator:
              type: string
              enum:
                - workflow_record
                - play
                - user
              description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
            play_sid:
              type: string
              nullable: true
              description: The play that bore the task (pt_pl_…); null on a journey's task.
            trigger_activity_sid:
              type: string
              nullable: true
              description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
            act:
              type: object
              nullable: true
              properties:
                do:
                  type: string
                  enum:
                    - send_message
                    - add_to_workflow
                    - like
                    - comment
                    - ask
                  description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                about:
                  type: string
                  enum:
                    - birthday
                    - work_anniversary
                    - job_change
                    - post
                    - website_visit
                    - event
                  description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                actor_sid:
                  type: string
                  description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                target_workflow_sid:
                  type: string
                  description: add_to_workflow, and a question whose move or add names one.
                post_urn:
                  type: string
                  description: "like, comment: the post the act goes to (an activity URN)."
                reaction:
                  type: string
                  description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                options:
                  type: array
                  items:
                    type: string
                    enum:
                      - remove
                      - keep
                      - move
                      - add
                  description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                suggested:
                  type: string
                  enum:
                    - remove
                    - keep
                    - move
                    - add
                  description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
              required:
                - do
                - about
              description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
            sender_profile_sid:
              type: string
              nullable: true
              description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
            assignee_user_sid:
              type: string
              nullable: true
              description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
            scheduled_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
            timeout_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
            dispatched_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped on scheduled → dispatched.
            expires_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once on any terminal status.
            variables_snapshot:
              type: object
              nullable: true
              additionalProperties:
                type: string
              description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
            result:
              type: object
              nullable: true
              additionalProperties: {}
              description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
            error_code:
              type: string
              nullable: true
              description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
            error_message:
              type: string
              nullable: true
              description: Human detail of the failure (max 1024); null on a skip.
            previous_attempts:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  attempt:
                    type: integer
                    description: The attempt number it was.
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                  error_code:
                    type: string
                    nullable: true
                    description: Its reason token.
                  error_message:
                    type: string
                    nullable: true
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                required:
                  - attempt
                  - status
                  - error_code
                  - error_message
                  - result
                  - dispatched_at
                  - finished_at
              description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
            created_at:
              type: string
              description: ISO 8601 UTC - the planning moment.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - workflow_record_sid
            - people_sid
            - step_id
            - type
            - attempt
            - status
            - initiator
            - play_sid
            - trigger_activity_sid
            - act
            - sender_profile_sid
            - assignee_user_sid
            - scheduled_at
            - timeout_at
            - dispatched_at
            - expires_at
            - finished_at
            - variables_snapshot
            - result
            - error_code
            - error_message
            - previous_attempts
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_completed:
              type: boolean
              description: true = idempotent repeat on an already-done manual task (no side effects; activity is null).
            activity:
              type: object
              nullable: true
              additionalProperties: {}
              description: Full manual_task_completed row (ActivityDomain - entities/activities.md; §4.12a embed); null on idempotent repeat and on a play's question.
            updated_workflow_record:
              type: object
              nullable: true
              additionalProperties: {}
              description: "The owning record AFTER the advance (WorkflowRecordDomain - entities/workflow_records.md): current_step_id / status show what happens next. A question about a journey: that record after the choice; null for a question about a person in no journey."
          required:
            - already_completed
            - activity
            - updated_workflow_record
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CreateCompanyRequest:
      type: object
      description: Request body of `create_company`.
      properties:
        playtable_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: "Table to attach to; omitted → playtable_sids: [] (table-less account - anchor for people.company_sid links)."
        name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 511
          description: Display name, a manual observation (context), never a column. NOT a dedup key - a name-only company skips the dedup ladder.
        logo_url:
          type: string
          nullable: true
          maxLength: 2048
          format: uri
          description: Company logo URL (max 2048), a manual observation; null = the domain favicon.
        ln_id:
          type: string
          nullable: true
          maxLength: 255
          description: Numeric LinkedIn company id - strongest dedup key.
        ln_nickname:
          type: string
          nullable: true
          maxLength: 255
          description: "Company page slug or page URL (reduced to the slug on write; a person profile or free text is a 422); dedup key #2."
        website:
          type: string
          nullable: true
          maxLength: 511
          format: uri
          description: The full URL, a manual observation; domain (a column, the identifier) is derived from it when domain is absent.
        domain:
          type: string
          nullable: true
          maxLength: 255
          description: "Normalized to lowercased apex on write; public-suffix validated; dedup key #3."
        deal_size:
          type: number
          nullable: true
          description: Deal value (decimal 15,2).
        tag_sids:
          type: array
          nullable: true
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Labels; each existence-checked (422 relation_not_found).
        external_refs:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Free-form CRM sync hook; round-tripped as-is.
        on_duplicate:
          type: string
          enum:
            - skip
            - attach
          description: "Dedup resolution: omitted → duplicate = 409 duplicate_rejected with context; \"skip\" = return the existing row untouched; \"attach\" = union playtable_sid into the existing row's membership (requires playtable_sid). Companies attach, never move."
    CreateCompanyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreateDataSourceRequest:
      type: object
      description: Request body of `create_data_source`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Target table (pt_tb_…) receiving promoted objects. Required for every kind.
        type:
          type: string
          enum:
            - ai_search
            - sender_search
            - post_engagement
            - find_people
            - csv
            - webhook
          description: "Required. ai_search | sender_search | post_engagement | find_people | webhook. `csv` is accepted by the shape rule and then refused with the way in: upload the file through upload-csv, then confirm it with import_data_source."
        url:
          type: string
          maxLength: 2048
          format: uri
          description: "LinkedIn link of an ai_search, sender_search or post_engagement: /search/results, /sales/search, /sales/lists, /talent/search?searchHistoryId=, /mynetwork, /messaging; post_engagement: /posts, /feed/update, lnkd.in, /in/{slug}, /company/{slug}."
        object_type:
          type: string
          enum:
            - people
            - company
          description: "What the rows become: people | company. Required for a description-mode ai_search. Elsewhere optional and checked for agreement with the link (or with the kind: find_people and webhook always bring people)."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: 'Defaults from the kind and its link ("Sales Navigator saved search", "My network", "AI search: <the description>").'
        sender_profile_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: The sender profile whose own LinkedIn account collects (ub_sp_); required for sender_search and post_engagement, prohibited elsewhere. Must be live, hold a LinkedIn account and the licence the link needs (Sales Navigator, or an active Recruiter session).
        payload:
          type: object
          properties:
            prompt:
              type: string
              maxLength: 2000
              description: "ai_search, find_people. Who to find, in words. ai_search: a prompt that is only an http(s) link is read as the link. find_people: empty = everyone at each company. Planned into the search filter at the first collect; no filter from it = plan_failed."
            filters:
              type: object
              additionalProperties: {}
              description: "ai_search, find_people. The by-params filter set plan_data_source_filters returns: it IS the plan, so planning is skipped (prompt may ride as the description). For find_people current companies are injected per anchor, never here."
            surface:
              type: string
              enum:
                - search
                - saved_search
                - list
                - post
                - my_network
                - messenger
              description: sender_search only. my_network (the profile's 1st-degree connections) or messenger (its conversation partners) is how a sender search runs WITHOUT a url. Sent with a url it must agree with what the link is (422 on payload.surface, rule agreement).
            repeat:
              type: string
              nullable: true
              enum:
                - hourly
                - daily
                - weekly
                - monthly
              description: "sender_search, post_engagement. hourly | daily | weekly | monthly = run again at that interval, bringing what is new (a post engagement: new people on the post, or new posts in the window); null or absent = once. Pool kinds never repeat."
            target:
              type: string
              enum:
                - post
                - person
                - company
              description: "post_engagement only. What the link must be: post | person | company; refused when the link is something else (422 on payload.target, rule agreement). Absent = read off the link."
            window:
              anyOf:
                - type: object
                  properties:
                    days:
                      anyOf:
                        - type: number
                          enum:
                            - 7
                        - type: number
                          enum:
                            - 30
                        - type: number
                          enum:
                            - 90
                  required:
                    - days
                  additionalProperties: false
                - type: object
                  properties:
                    since:
                      type: string
                      pattern: ^\d{4}-\d{2}-\d{2}$
                  required:
                    - since
                  additionalProperties: false
              description: 'post_engagement, a person or a company only: {days: 7 | 30 | 90} back from each run (default 30), or {since: "YYYY-MM-DD"} within the past year. On one post it is 422 rule prohibited.'
            relevance:
              type: object
              nullable: true
              properties:
                prompt:
                  type: string
                  minLength: 1
                  maxLength: 2000
              required:
                - prompt
              additionalProperties: false
              description: "post_engagement only. The AI post filter: which posts count, in the user's words (\"posts about outbound; skip job ads\"). One llm.generate per 20 posts, billed as the source's check; a post it could not judge passes. null or absent = every post is walked."
            collect:
              type: object
              properties:
                reactions:
                  type: boolean
                comments:
                  type: boolean
                reposts:
                  type: boolean
              additionalProperties: false
              description: post_engagement only. {reactions, comments, reposts}, each true or false; absent switches default to reactions and comments on, reposts off; all three off is 422 rule required.
            company_sids:
              type: array
              items:
                type: string
                minLength: 18
                maxLength: 18
                pattern: ^cr_co_
              minItems: 1
              maxItems: 500
              description: "find_people only; required there unless company_filter is given. The companies to find people at (cr_co_, from the companies grid), at most 500 per source: over the cap is 422 rule max. Grow the queue with add_companies_to_data_source."
            company_filter:
              type: object
              additionalProperties: {}
              description: "find_people only. An account filter instead of (or with) company_sids: the search_companies filter object as is, resolved to sids at the call (a disqualified account is left out). No match and no sids is 422 rule required; past 500 matches 422 rule max."
            per_company_limit:
              type: integer
              minimum: 1
              maximum: 25
              description: find_people only. People taken per company (1..25); absent = the whole first search page (25).
            records_path:
              type: string
              description: webhook only. Where the array of records sits in an inbound body ("data.contacts"); absent = the body is the record or the array itself.
          description: "The kind's own keys: ai_search {prompt | filters}, sender_search {surface, repeat}, post_engagement {target, window, relevance, collect, repeat}, find_people {company_sids, company_filter, per_company_limit, prompt, filters}, webhook {records_path}."
        field_mapping:
          type: array
          items:
            type: object
            properties:
              source:
                type: string
                minLength: 1
                maxLength: 512
                description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
              target_kind:
                type: string
                enum:
                  - people_attribute
                  - company_attribute
                  - field_slug
                description: people_attribute | company_attribute | field_slug.
              target:
                type: string
                minLength: 1
                maxLength: 255
                description: Attribute key (people / company) or a playtable field slug in the target table.
              name:
                type: string
                nullable: true
                minLength: 1
                maxLength: 255
                description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
            required:
              - source
              - target_kind
              - target
          description: Optional override for type=webhook (absent = attribute auto-detect at promotion); prohibited for the three search kinds, whose collector emits the canonical parser shape. A csv source gets its mapping at import.
        tag_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Each tag must exist (cr_tg_…); applied to every promoted object.
        on_duplicate:
          type: string
          enum:
            - skip
            - move
          description: Default 'skip'.
        add_tags_to_duplicate:
          type: boolean
          description: Default false - merge tag_sids onto matched duplicates.
        qualify:
          type: object
          nullable: true
          properties:
            "on":
              type: boolean
              description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
            criterion:
              type: string
              nullable: true
              minLength: 1
              maxLength: 2000
              description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
          required:
            - "on"
            - criterion
          additionalProperties: false
          description: 'The source gate, "Check on save": {on, criterion}. A closed object (an unknown key is 422 rule invalid_qualify); on with no words is refused.'
      required:
        - playtable_sid
        - type
    CreateDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        ingest_url:
          type: string
          description: "type=webhook only: {api_base}/external/ingest/{ingest_key} - the endpoint the customer CRM POSTs records to. The URL IS the credential: hand it to the user over a channel they trust, and rotate it to revoke."
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreateDataSourceUploadUrlRequest:
      type: object
      description: Request body of `create_data_source_upload_url`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Target table (pt_tb_…) the draft feeds; checked at the mint, a missing or foreign one is 422 relation_not_found before any bytes travel.
        object_type:
          type: string
          enum:
            - people
            - company
          description: "What the rows become: people (default) | company; import_data_source may still override it."
        mode:
          type: string
          enum:
            - create
            - update
          description: "What the import does with them: create (default) | update; import_data_source may still override it."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: "The draft's name; default: the file name the PUT declares in Content-Disposition, else upload.csv."
        tag_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Tags every promoted row gets (cr_tg_…, must exist in the team; checked at the mint).
        qualify:
          type: object
          nullable: true
          properties:
            "on":
              type: boolean
              description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
            criterion:
              type: string
              nullable: true
              minLength: 1
              maxLength: 2000
              description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
          required:
            - "on"
            - criterion
          additionalProperties: false
          description: "The source gate, Check on save: {on, criterion}; null or absent = no check. import_data_source may still set it."
        on_duplicate:
          type: string
          enum:
            - skip
            - move
          description: "skip (default) | move: what a person already in another table does."
        add_tags_to_duplicate:
          type: boolean
          description: Merge tag_sids onto a matched duplicate; default false.
      required:
        - playtable_sid
    CreateDataSourceUploadUrlResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            upload_url:
              type: string
              description: The signed URL to PUT the bytes to, used exactly as given (the signature covers the path and the query); one use, then gone.
            method:
              type: string
              enum:
                - PUT
            expires_at:
              type: string
              description: "ISO 8601 UTC: the link stops working here, 15 minutes after the mint; mint again after it."
            max_bytes:
              type: integer
              minimum: 0
              exclusiveMinimum: true
              description: The body cap in bytes (51200 KB, the multipart rule); a larger PUT is 422 on file.
            content_types:
              type: array
              items:
                type: string
              description: The Content-Type values the PUT accepts (text/csv, text/plain); the bytes are sniffed too, so a non-CSV body is 422 whatever it declares.
          required:
            - upload_url
            - method
            - expires_at
            - max_bytes
            - content_types
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CreateNoteRequest:
      type: object
      description: Request body of `create_note`.
      properties:
        object_type:
          type: string
          enum:
            - person
            - company
            - workflow
          description: "Kind of the object: 'person', 'company', or 'workflow' for a sticker on its canvas. Must match the object_sid prefix (422 validation_failed otherwise)."
        object_sid:
          type: string
          minLength: 18
          maxLength: 18
          description: The person (cr_pp_…), company (cr_co_…) or workflow (wf_wf_…) to pin the note to. Prefix must match object_type (422 validation_failed). Must be live and same-team (422 relation_not_found otherwise). Immutable after create.
        body:
          type: string
          maxLength: 65535
          description: 'Plain-text note body. Rendered as-is - no rich text, no attachments, no @-mentions. 1..65535 chars on a person or company; a sticker may be empty (""). On a sticker: two or three short sentences explaining a choice or a risk of that step.'
        step_id:
          type: integer
          nullable: true
          minimum: 1
          description: "A sticker only: the id of the workflow step it explains, from the workflow's saved steps (422 validation_failed for a step the workflow does not have). Omit for the sticker about the whole workflow. Never on a person or company note."
        position:
          type: object
          nullable: true
          properties:
            x:
              type: integer
              minimum: -50000
              maximum: 50000
            "y":
              type: integer
              minimum: -50000
              maximum: 50000
          required:
            - x
            - "y"
          additionalProperties: false
          description: "A sticker only, and set by the canvas when a person drags it: leave it out. Without it the canvas places the sticker beside its step."
      required:
        - object_type
        - object_sid
        - body
    CreateNoteResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: Note sid (cr_nt_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            object_type:
              type: string
              enum:
                - person
                - company
                - workflow
              description: "Kind of the annotated object: person | company | workflow (a sticker on its canvas). Fixed at create - a note is never re-homed."
            object_sid:
              type: string
              description: The annotated person (cr_pp_…), company (cr_co_…) or workflow (wf_wf_…); prefix matches object_type.
            body:
              type: string
              description: Plain-text note body, rendered as-is; FULLTEXT-indexed for filter.q. 1..65535 chars on a person or company; a sticker may be empty.
            step_id:
              type: integer
              nullable: true
              description: "A sticker only: the workflow step it sits beside; null = the workflow as a whole (and always null on a person or company note)."
            position:
              type: object
              nullable: true
              properties:
                x:
                  type: integer
                  minimum: -50000
                  maximum: 50000
                "y":
                  type: integer
                  minimum: -50000
                  maximum: 50000
              required:
                - x
                - "y"
              additionalProperties: false
              description: "A sticker only: where a person dragged it, relative to its step; null = the canvas places it beside its step."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that authored the note (AccessIdentityValue); shown for accountability.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the note (tool call or parent cascade); null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC; bumped by body edits.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - object_type
            - object_sid
            - body
            - step_id
            - position
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePersonRequest:
      type: object
      description: Request body of `create_person`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Target table (pt_tb_…) - the person's single membership.
        full_name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: "Display name, 1..255: a manual observation (it outranks every source until reset), never a column; null = unnamed until a source names the row."
        avatar_url:
          type: string
          nullable: true
          maxLength: 2048
          format: uri
          description: "Profile photo URL (max 2048): a manual observation like full_name, never a column; null = no picture known."
        ln_member_id:
          type: string
          nullable: true
          maxLength: 255
          description: LinkedIn member urn id - strongest dedup key.
        ln_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw LinkedIn profile URN (ACoAA…); no spaces. Decodes to ln_member_id.
        sn_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw Sales Navigator URN (ACwAA…); no spaces. Decodes to the same ln_member_id.
        recruiter_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw Recruiter URN (AEMAA…); no spaces. Decodes to the same ln_member_id.
        ln_nickname:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: "Vanity slug, or a profile URL: the service reduces a URL to its axis (a slug, or a URN moved to ln_id / sn_id / recruiter_id) and never stores the URL (SERVICE_CONVENTIONS §Y). Counts as contact data; dispatch still needs a URN."
        work_email:
          type: string
          nullable: true
          format: email
          description: Stored lowercased - 3rd dedup key (with personal_email).
        personal_email:
          type: string
          nullable: true
          format: email
          description: Personal address; stored lowercased, a dedup key together with work_email.
        work_phone_number:
          type: string
          nullable: true
          maxLength: 255
          description: Plain string, E.164 preferred.
        personal_phone_number:
          type: string
          nullable: true
          maxLength: 255
          description: Plain string, E.164 preferred; richer phone sets are field values.
        company_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^cr_co_
          description: Must exist; the person's company then resolves from the account (context.company).
        company_name:
          type: string
          nullable: true
          maxLength: 255
          description: A name that is not an account, a manual observation; read only when company_sid is absent.
        tag_sids:
          type: array
          nullable: true
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Each tag must exist (cr_tg_…).
        external_refs:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Free-form CRM sync map; keys integration-defined, stored as-is.
        on_duplicate:
          type: string
          enum:
            - skip
            - move
          description: "skip = return the existing row; move = re-home it into playtable_sid. Applies on BOTH dedup tiers when given. Omitted: an identity-tier hit is 409, a flag-tier match (nickname, phone) is born flagged."
      required:
        - playtable_sid
    CreatePersonResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              description: pt_tb_… - the SINGLE playtable membership; service-managed, changes only via move (create on_duplicate:move / run type move).
            data_source_sid:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            company_sid:
              type: string
              nullable: true
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                first_name:
                  type: string
                  nullable: true
                  description: The source's own first name when it gave one, else the first word of name.
                picture_url:
                  type: string
                  nullable: true
                  description: A permanent copy over a wire link, the wire link that lasts longest, an expired one counts as none.
                role:
                  type: string
                  nullable: true
                  description: The title at the company (the Sales Navigator wire's position, the enrichment's).
                headline:
                  type: string
                  nullable: true
                  description: The profile line (the regular and Recruiter wires, the inbox participant, the enrichment).
                company:
                  type: object
                  nullable: true
                  properties:
                    sid:
                      type: string
                      nullable: true
                      description: cr_co_… when the person is linked to an account (the account's own resolved context follows); null = a name that is not an account, an import whose company column resolved to none.
                    name:
                      type: string
                      nullable: true
                    domain:
                      type: string
                      nullable: true
                    picture_url:
                      type: string
                      nullable: true
                    ln_id:
                      type: string
                      nullable: true
                      description: "The company's LinkedIn id: the linked account's own, else the person's company id as a source or an edit gave it."
                  required:
                    - sid
                    - name
                    - domain
                    - picture_url
                    - ln_id
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - first_name
                - picture_url
                - role
                - headline
                - company
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, first name, picture, role, headline and company a surface or a model shows next to the row, resolved at read from the observations ledger: a manual word until reset, then the newest LinkedIn-derived observation, then any other. The only place these words are: the row keeps identifiers (phase E, 2026-10-22). Null only on an event payload."
            ln_member_id:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
            sn_id:
              type: string
              nullable: true
            recruiter_id:
              type: string
              nullable: true
            work_email:
              type: string
              nullable: true
            personal_email:
              type: string
              nullable: true
            work_phone_number:
              type: string
              nullable: true
            personal_phone_number:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - no_contact_data
                - duplicate
                - stoplisted
              description: Service-managed row validity (import validation, stoplist, duplicate detection) - not client-writable.
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY row (cr_pp_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_person_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_member_id
                - ln_id
                - sn_id
                - recruiter_id
                - email
                - ln_nickname
                - phone
              description: "While status is duplicate: the identifier the check matched on. Null otherwise."
            linkedin_status:
              type: string
              enum:
                - need_enrichment
                - enrichment_failed
                - no_data
                - blocked
                - ok
            email_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - bounced
                - ok
                - catch_all
                - unverified
            phone_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - ok
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: Free-form CRM sync map (hubspot_contact_id, …) - keys integration-defined, round-tripped as-is; PHP empty map serialises as [].
            last_enrich_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: The funnel stage the person is in (cr_ps_...), derived from activity or moved by hand (pipeline_stages.md); null = no stage.
          required:
            - sid
            - team_sid
            - playtable_sid
            - data_source_sid
            - data_source_item_sid
            - company_sid
            - context
            - ln_member_id
            - ln_id
            - sn_id
            - recruiter_id
            - work_email
            - personal_email
            - work_phone_number
            - personal_phone_number
            - status
            - duplicate_of_sid
            - duplicate_matched_kind
            - linkedin_status
            - email_status
            - phone_status
            - tag_sids
            - external_refs
            - last_enrich_at
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePipelineStageRequest:
      type: object
      description: Request body of `create_pipeline_stage`.
      properties:
        object:
          type: string
          enum:
            - person
            - company
          description: "Which pipeline to append the stage to: person (leads) or company (accounts). Immutable afterwards."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Stage label, 1..255. Must not collide with a live stage of the same (team, object), compared case-insensitively (409 duplicate_rejected, context.existing_sid).
        category:
          type: string
          enum:
            - cold
            - approaching
            - engaging
            - positive
            - nurture
            - negative
            - disqualified
          description: Funnel bucket for the new stage. Drives the chip color and, for a person stage, what a company derives from a member sitting here.
      required:
        - object
        - name
        - category
    CreatePipelineStageResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: Pipeline stage sid (cr_ps_…) - the value people.pipeline_stage_sid / companies.pipeline_stage_sid store.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            object:
              type: string
              enum:
                - person
                - company
              description: "Which pipeline this stage belongs to: person (leads) | company (accounts). Immutable after create."
            name:
              type: string
              description: Stage label (1..255), unique per (team, object) among live rows, case-insensitively.
            category:
              type: string
              enum:
                - cold
                - approaching
                - engaging
                - positive
                - nurture
                - negative
                - disqualified
              description: "Funnel bucket, one of seven: the grouping of the company card and the grid, the chip colour, the funnel analytics and the company derivation (positive > engaging > approaching > nurture > negative > cold; a person on a disqualified stage is not an active member of the account). negative = a real no (Not interested); disqualified = not a target, filtered out (Wrong Decision Maker, Disqualified). Locked on a system stage (key != null)."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the stage (AccessIdentityValue); the seeded system stages carry the system identity.
            key:
              type: string
              nullable: true
              description: "Stable snake_case anchor on SYSTEM stages ('new_contact', 'company_opportunity', …), the target the auto-transition engine resolves; null = a custom stage. key != null is what makes a stage system: locked category, non-deletable. Read-only."
            order:
              type: integer
              nullable: true
              description: Position within its (team, object) pipeline, contiguous 1..N, and the forward-only rank for a person (a target stage is only auto-entered when its order >= the current one). 0 = pulled out of the ordering (a soft-deleted row).
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC; bumped by rename / recategorize / reorder.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - object
            - name
            - category
            - created_by
            - key
            - order
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePlayRequest:
      type: object
      description: Request body of `create_play`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: The table the play lives in; its audience is resolved inside it.
        catalog_key:
          type: string
          enum:
            - keep_fresh
            - congratulate
            - on_job_change
            - engage_posts
            - on_website_visit
            - find_people_empty
            - top_up_thin
            - top_up_silent
            - top_up_no_reply
            - top_up_exhausted
            - find_decision_maker
            - reengage_dormant
            - reach_untouched
          description: "A playbook play: the entry gives object, audience, action and name, so send only the table (plus action.workflow_sid for a people play; cadence, switch, ceiling if wanted). Born once per table: a repeat answers the existing row, already_exists true."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Required without catalog_key; with it, a name over the entry's.
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Required without catalog_key. What the audience selects: company for find_people, people for add_to_workflow (422 otherwise)."
        action_type:
          type: string
          enum:
            - find_people
            - add_to_workflow
            - refresh
            - congratulate
            - on_job_change
            - engage_posts
            - on_website_visit
          description: Required without catalog_key.
        action:
          type: object
          properties:
            prompt:
              type: string
              nullable: true
              maxLength: 2000
              description: "find_people: who to find at each account; absent on a playbook play = the entry's default, empty otherwise = everyone the page gives."
            per_company_limit:
              type: integer
              nullable: true
              minimum: 1
              maximum: 25
              description: "find_people: people per account; absent on a playbook play = the entry's default, absent otherwise = the whole first page."
            workflow_sid:
              type: string
              nullable: true
              minLength: 18
              maxLength: 18
              pattern: ^wf_wf_
              description: "add_to_workflow: the workflow the audience enters, the team's, live, published (409 otherwise); the play's manual source is born in it. Omit to pick it later with update_play: until then the play neither estimates, runs nor switches on."
            moments:
              type: object
              properties:
                birthday:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
                work_anniversary:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
                job_change:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
              description: "congratulate: the moments over the entry's defaults, each key deep (one moment's own keys over its default)."
            do:
              type: string
              description: "on_job_change: pause_and_ask | remove_from_workflows | move_to_workflow; on_website_visit: pause_and_ask | add_to_workflow."
            like:
              type: object
              properties:
                "on":
                  type: boolean
                reaction:
                  type: string
                  enum:
                    - ai
                    - like
                    - celebrate
                    - support
                    - love
                    - insightful
                    - funny
                  description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
              required:
                - "on"
                - reaction
            comment:
              type: object
              properties:
                "on":
                  type: boolean
                brief:
                  type: string
                  nullable: true
                  maxLength: 2000
                  description: What the AI writes the comment from; required while on.
              required:
                - "on"
                - brief
            per_person_weekly_cap:
              type: integer
              minimum: 1
              maximum: 14
            sender_profile_sid:
              type: string
              nullable: true
              description: "engage_posts: who acts on a person connected to no sender profile."
            pages:
              type: array
              nullable: true
              items:
                type: string
          description: "The action's parameters (required without catalog_key), the keys of the action_type over the entry's defaults. The sids of the play's sources are never sent: the server births them. A workflow a typed action names must be the team's, live and published."
        watch:
          type: object
          nullable: true
          properties:
            profile_days:
              anyOf:
                - type: number
                  enum:
                    - 7
                - type: number
                  enum:
                    - 14
                - type: number
                  enum:
                    - 30
                - type: number
                  enum:
                    - 90
                - {}
              description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
            company_days:
              anyOf:
                - type: number
                  enum:
                    - 30
                - type: number
                  enum:
                    - 90
                - {}
              description: "The company page every N days: 30 | 90; null = not watched."
            posts_days:
              anyOf:
                - type: number
                  enum:
                    - 1
                - type: number
                  enum:
                    - 3
                - type: number
                  enum:
                    - 7
                - {}
              description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
            moments:
              type: boolean
              description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
          description: What the play keeps refreshed; absent on a playbook play = the entry's; a cadence outside the product's own is 422; null = nothing.
        mode:
          type: string
          enum:
            - ask_me
            - automatic
          description: ask_me | automatic; absent on a playbook play = the entry's (ask me for the plays that act).
        audience:
          description: "Without catalog_key: the tab's filter AST, validated like a saved view. Signals by name: {field: signals, op: {in: [no_engagement]}}; the category: {field: pipeline_stage_category, op: {in: [nurture]}}; several under {and: [...]}. Omit = the whole tab."
        cadence:
          type: string
          enum:
            - manual
            - daily
          description: Default manual.
        enabled:
          type: boolean
          description: "daily only: true is the consent, stated with the estimate; the first run follows within the minute. 422 on a manual play."
        daily_credit_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "find_people only: what one day may spend. 422 on an add_to_workflow play."
      required:
        - playtable_sid
    CreatePlayResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: Play sid (pt_pl_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…).
            playtable_sid:
              type: string
              description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
            catalog_key:
              type: string
              nullable: true
              enum:
                - keep_fresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
                - find_people_empty
                - top_up_thin
                - top_up_silent
                - top_up_no_reply
                - top_up_exhausted
                - find_decision_maker
                - reengage_dormant
                - reach_untouched
              description: The playbook entry the row was born from; null = a play saved from a view's filter.
            name:
              type: string
              description: The play's name, 1..255.
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What the audience selects: people, or company (accounts)."
            action_type:
              type: string
              enum:
                - find_people
                - add_to_workflow
                - refresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
              description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
            action:
              anyOf:
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                    per_company_limit:
                      type: integer
                      nullable: true
                      description: People taken per account, 1..25; null = the whole first page.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                    workflow_source_sid:
                      type: string
                      nullable: true
                      description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                  required:
                    - workflow_sid
                    - workflow_source_sid
                - type: object
                  properties:
                    moments:
                      type: object
                      properties:
                        birthday:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        work_anniversary:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        job_change:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                      description: A switch per moment with its own Do under it; a kind absent is off.
                  required:
                    - moments
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - remove_from_workflows
                        - move_to_workflow
                      description: For a person in a workflow whose title or company moved.
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                  required:
                    - do
                    - workflow_sid
                - type: object
                  properties:
                    like:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        reaction:
                          type: string
                          enum:
                            - ai
                            - like
                            - celebrate
                            - support
                            - love
                            - insightful
                            - funny
                          description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                      required:
                        - "on"
                        - reaction
                    comment:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        brief:
                          type: string
                          nullable: true
                          maxLength: 2000
                          description: What the AI writes the comment from; required while on.
                      required:
                        - "on"
                        - brief
                    per_person_weekly_cap:
                      type: integer
                      minimum: 1
                      maximum: 14
                      description: At most this many acts a week per person.
                    sender_profile_sid:
                      type: string
                      nullable: true
                      description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                  required:
                    - like
                    - comment
                    - per_person_weekly_cap
                    - sender_profile_sid
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - add_to_workflow
                      description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: required when the Do is a workflow."
                    pages:
                      type: array
                      nullable: true
                      items:
                        type: string
                      description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                  required:
                    - do
                    - workflow_sid
                    - pages
                - type: object
                  properties: {}
                  description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
              description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
            audience:
              description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
            watch:
              type: object
              nullable: true
              properties:
                profile_days:
                  anyOf:
                    - type: number
                      enum:
                        - 7
                    - type: number
                      enum:
                        - 14
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                company_days:
                  anyOf:
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The company page every N days: 30 | 90; null = not watched."
                posts_days:
                  anyOf:
                    - type: number
                      enum:
                        - 1
                    - type: number
                      enum:
                        - 3
                    - type: number
                      enum:
                        - 7
                    - {}
                  description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                moments:
                  type: boolean
                  description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
              required:
                - profile_days
                - company_days
                - posts_days
                - moments
              description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
            cadence:
              type: string
              enum:
                - manual
                - daily
              description: "manual: runs on run_play; daily: runs by itself every day while enabled."
            mode:
              type: string
              enum:
                - ask_me
                - automatic
              description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
            enabled:
              type: boolean
              description: The switch of a daily play; a manual play is always false.
            enabled_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Who gave the consent (switched the play on).
            enabled_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when."
            daily_credit_limit:
              type: integer
              nullable: true
              description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
            last_run_at:
              type: string
              nullable: true
              description: ISO 8601 UTC.
            last_run_counts:
              type: object
              nullable: true
              properties:
                matched:
                  type: integer
                  minimum: 0
                  description: Rows the audience matched at the run (the tab's count under the filter).
                acted:
                  type: integer
                  minimum: 0
                  description: Accounts appended to the queue, or people entered or re-entered.
                skipped:
                  type: integer
                  minimum: 0
                  description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                credits:
                  type: integer
                  minimum: 0
                  description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
              required:
                - matched
                - acted
                - skipped
                - credits
              description: What the last run did; null before the first run.
            next_run_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live.
          required:
            - sid
            - team_sid
            - playtable_sid
            - catalog_key
            - name
            - object_type
            - action_type
            - action
            - watch
            - cadence
            - mode
            - enabled
            - enabled_by
            - enabled_at
            - daily_credit_limit
            - last_run_at
            - last_run_counts
            - next_run_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePlaytableFieldRequest:
      type: object
      description: Request body of `create_playtable_field`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Object grid this field belongs to: people or company rows. Fixed at create."
        type:
          type: string
          enum:
            - scalar_text
            - scalar_number
            - scalar_currency
            - scalar_date
            - scalar_url
            - scalar_checkbox
            - scalar_select
            - scalar_multiselect
            - scalar_image
            - widget_data_source
            - widget_tags
            - widget_active_workflows
            - widget_notes
            - widget_company
            - widget_linkedin_id
            - widget_linkedin_channel
            - widget_work_email
            - widget_personal_email
            - widget_email_channel
            - widget_phones
            - widget_phone_channel
            - widget_last_touch
            - widget_activity
            - widget_deal_size
            - widget_website
            - widget_people_summary
            - widget_ai_sdr
            - action_ai_research
            - action_waterfall
            - action_gtm_tool
            - action_find_people
          description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Display label; slug is derived from it when slug is omitted.
        slug:
          type: string
          minLength: 1
          maxLength: 64
          pattern: ^[a-z][a-z0-9_]{0,63}$
          description: "Template-variable name, immutable after create: formulas read record.<slug>, prompts {{record.<slug>}}. Default: the slugified name (a collision takes _2)."
        payload:
          anyOf:
            - type: object
              properties:
                formula:
                  type: string
                  nullable: true
                  maxLength: 8192
                  description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                template:
                  type: string
                  nullable: true
                  maxLength: 8192
                  description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                nl_formula:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                options:
                  type: array
                  nullable: true
                  items:
                    type: string
                  minItems: 1
                  description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                currency:
                  type: string
                  nullable: true
                  pattern: ^[A-Z]{3}$
                  description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                option_colors:
                  type: object
                  nullable: true
                  additionalProperties:
                    type: string
                    pattern: ^#[0-9a-f]{6}$
                  description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
              required:
                - formula
                - template
                - nl_formula
                - options
                - currency
                - option_colors
            - type: object
              properties: {}
              additionalProperties: false
              description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
            - type: object
              properties:
                workflow_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
              required:
                - workflow_sid
              additionalProperties: false
            - type: object
              properties:
                stats_view:
                  type: string
                  enum:
                    - all
                    - last
                    - select
                  description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                sender_profile_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                  description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
              required:
                - stats_view
                - sender_profile_sid
              additionalProperties: false
            - type: object
              properties:
                prompt:
                  type: string
                  minLength: 1
                  maxLength: 8192
                  description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                model:
                  type: string
                  minLength: 1
                  maxLength: 128
                  description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                output:
                  type: string
                  enum:
                    - text
                    - number
                    - select
                    - json
                  description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                options:
                  type: array
                  nullable: true
                  items:
                    type: string
                  minItems: 1
                  description: Required (min 1) when output=select; null otherwise.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                web_search:
                  type: boolean
                  description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
              required:
                - prompt
                - model
                - output
                - options
                - output_mapping
            - type: object
              properties:
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      tool_sid:
                        type: string
                        minLength: 1
                        description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                      params:
                        type: object
                        additionalProperties: {}
                        description: Tool params; string values may be Twig templates over the same variable namespace.
                    required:
                      - tool_sid
                      - params
                  maxItems: 10
                  description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                stop_on_first:
                  type: boolean
                  description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                verify:
                  type: object
                  nullable: true
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                  required:
                    - tool_sid
                    - params
                  description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                accept_catch_all:
                  type: boolean
                  description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
              required:
                - steps
                - stop_on_first
                - output_mapping
            - type: object
              properties:
                tool_sid:
                  type: string
                  minLength: 1
                  description: gtm-api tool registry sid (external format); existence + price validated at save.
                params:
                  type: object
                  additionalProperties: {}
                  description: Tool params; string values may be Twig templates over the same variable namespace.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
              required:
                - tool_sid
                - params
                - output_mapping
            - type: object
              properties:
                prompt:
                  type: string
                  nullable: true
                  maxLength: 2000
                  description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                per_company_limit:
                  type: integer
                  minimum: 1
                  maximum: 25
                  description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                data_source_sid:
                  type: string
                  nullable: true
                  description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                qualify:
                  type: object
                  nullable: true
                  properties:
                    "on":
                      type: boolean
                      description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                    criterion:
                      type: string
                      nullable: true
                      minLength: 1
                      maxLength: 2000
                      description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                  required:
                    - "on"
                    - criterion
                  additionalProperties: false
                  description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
              required:
                - prompt
                - per_company_limit
                - data_source_sid
          description: "Shape must match type. REQUIRED for action_* types; default: {} (widget) / all-null scalar payload."
        config:
          type: object
          properties:
            auto_run:
              type: boolean
              description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
            run_condition:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                        is_null:
                          type: boolean
                        contains:
                          type: string
                          minLength: 1
                        not_contains:
                          type: string
                          minLength: 1
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        starts_with:
                          type: string
                          minLength: 1
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
            nl_condition:
              type: string
              nullable: true
              maxLength: 2048
              description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
            daily_credit_limit:
              type: integer
              nullable: true
              minimum: 0
              exclusiveMinimum: true
              description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
            preset_sid:
              type: string
              nullable: true
              description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
          required:
            - auto_run
            - run_condition
            - nl_condition
            - daily_credit_limit
            - preset_sid
          description: Action fields only. Omit for defaults (auto_run:false, everything else null).
        add_to_default_view:
          type: boolean
          description: "true also appends the column to its grid's default view, so people see it without an update_playtable_view call. Idempotent: a column already in the layout stays where it is. Default false: the column exists but no view shows it."
      required:
        - playtable_sid
        - object_type
        - type
        - name
    CreatePlaytableFieldResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object grid this field belongs to: people or company rows. Fixed at create."
            name:
              type: string
              description: Display label, freely editable.
            slug:
              type: string
              description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
            category:
              type: string
              enum:
                - scalar
                - widget
                - action
              description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
            type:
              type: string
              enum:
                - scalar_text
                - scalar_number
                - scalar_currency
                - scalar_date
                - scalar_url
                - scalar_checkbox
                - scalar_select
                - scalar_multiselect
                - scalar_image
                - widget_data_source
                - widget_tags
                - widget_active_workflows
                - widget_notes
                - widget_company
                - widget_linkedin_id
                - widget_linkedin_channel
                - widget_work_email
                - widget_personal_email
                - widget_email_channel
                - widget_phones
                - widget_phone_channel
                - widget_last_touch
                - widget_activity
                - widget_deal_size
                - widget_website
                - widget_people_summary
                - widget_ai_sdr
                - action_ai_research
                - action_waterfall
                - action_gtm_tool
                - action_find_people
              description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
            payload:
              anyOf:
                - type: object
                  properties:
                    formula:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                    template:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                    nl_formula:
                      type: string
                      nullable: true
                      maxLength: 2048
                      description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                    currency:
                      type: string
                      nullable: true
                      pattern: ^[A-Z]{3}$
                      description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                    option_colors:
                      type: object
                      nullable: true
                      additionalProperties:
                        type: string
                        pattern: ^#[0-9a-f]{6}$
                      description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                  required:
                    - formula
                    - template
                    - nl_formula
                    - options
                    - currency
                    - option_colors
                - type: object
                  properties: {}
                  additionalProperties: false
                  description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^wf_wf_
                      description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                  required:
                    - workflow_sid
                  additionalProperties: false
                - type: object
                  properties:
                    stats_view:
                      type: string
                      enum:
                        - all
                        - last
                        - select
                      description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                    sender_profile_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^ub_sp_
                      description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                  required:
                    - stats_view
                    - sender_profile_sid
                  additionalProperties: false
                - type: object
                  properties:
                    prompt:
                      type: string
                      minLength: 1
                      maxLength: 8192
                      description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                    model:
                      type: string
                      minLength: 1
                      maxLength: 128
                      description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                    output:
                      type: string
                      enum:
                        - text
                        - number
                        - select
                        - json
                      description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Required (min 1) when output=select; null otherwise.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                    web_search:
                      type: boolean
                      description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                  required:
                    - prompt
                    - model
                    - output
                    - options
                    - output_mapping
                - type: object
                  properties:
                    steps:
                      type: array
                      items:
                        type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                        required:
                          - tool_sid
                          - params
                      maxItems: 10
                      description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                    stop_on_first:
                      type: boolean
                      description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                    verify:
                      type: object
                      nullable: true
                      properties:
                        tool_sid:
                          type: string
                          minLength: 1
                          description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                        params:
                          type: object
                          additionalProperties: {}
                          description: Tool params; string values may be Twig templates over the same variable namespace.
                      required:
                        - tool_sid
                        - params
                      description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                    accept_catch_all:
                      type: boolean
                      description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                  required:
                    - steps
                    - stop_on_first
                    - output_mapping
                - type: object
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: gtm-api tool registry sid (external format); existence + price validated at save.
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                  required:
                    - tool_sid
                    - params
                    - output_mapping
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                    per_company_limit:
                      type: integer
                      minimum: 1
                      maximum: 25
                      description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                    qualify:
                      type: object
                      nullable: true
                      properties:
                        "on":
                          type: boolean
                          description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                        criterion:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 2000
                          description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                      required:
                        - "on"
                        - criterion
                      additionalProperties: false
                      description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
              description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                run_condition:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                nl_condition:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                daily_credit_limit:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
              required:
                - auto_run
                - run_condition
                - nl_condition
                - daily_credit_limit
                - preset_sid
            backfill:
              type: object
              nullable: true
              properties:
                status:
                  type: string
                  enum:
                    - queued
                    - running
                    - done
                    - failed
                scanned:
                  type: integer
                  minimum: 0
                  description: Objects the scan has visited so far.
                total:
                  type: integer
                  nullable: true
                  minimum: 0
                  description: The scan size, known once the job starts (null while queued).
                queued_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the column started owing its backfill."
                started_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the job took it."
                finished_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when it ended, done or failed."
                error:
                  type: string
                  nullable: true
                  description: A reason token (backfill_failed) on failed, never an exception message.
              required:
                - status
                - scanned
                - total
                - queued_at
                - started_at
                - finished_at
                - error
              description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - slug
            - category
            - type
            - payload
            - config
            - backfill
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePlaytableRequest:
      type: object
      description: Request body of `create_playtable`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Table name; unique per team - the dedup natural key.
        description:
          type: string
          nullable: true
          maxLength: 2000
          description: Free text about the table (max 2000), shown on it.
        config:
          type: object
          properties:
            auto_run:
              type: boolean
              description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
          required:
            - auto_run
          description: "Default { auto_run: false }."
        agent_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_ag_
          description: The AI SDR for this table (ub_ag_…, from search_agents on unibox); left out or null = the team's default agent. The prefix is all playtables checks.
      required:
        - name
    CreatePlaytableResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            company_default_view_sid:
              type: string
              description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
            people_default_view_sid:
              type: string
              description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
              required:
                - auto_run
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - agent_sid
            - company_default_view_sid
            - people_default_view_sid
            - config
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePlaytableRunRequest:
      type: object
      description: Request body of `create_playtable_run`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Parent playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Which tab the run targets: people | company."
        type:
          type: string
          enum:
            - enrich
            - export
            - import
            - bulk
          description: enrich (PAID - estimate first, set max_budget) | export | import | bulk. Branches which fields below are required.
        field_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
          minItems: 1
          maxItems: 20
          description: "REQUIRED for type=enrich, forbidden otherwise (422): 1..20 action columns (a widget, a plain column or a formula column is 422; a formula column fills through backfill_playtable_field instead)."
        scope:
          type: object
          properties:
            object_sids:
              type: array
              nullable: true
              items:
                type: string
                minLength: 18
                maxLength: 18
              minItems: 1
              description: "Explicit targets (cr_pp_… / cr_co_… of the run object_type), min 1, max 10 000 (a wider selection is a view/filter, optionally with exclude_object_sids). Exactly one scope form: XOR with view_sid/filter - both or neither → 422."
            view_sid:
              type: string
              nullable: true
              minLength: 18
              maxLength: 18
              pattern: ^pt_vw_
              description: Saved view (pt_vw_…) - its filter AST is snapshotted into the run at create; later view edits do not retarget. Combinable with filter; XOR with object_sids.
            exclude_object_sids:
              type: array
              nullable: true
              items:
                type: string
                minLength: 18
                maxLength: 18
              maxItems: 10000
              description: Rows of the view/filter form to leave out (select all minus the unticked rows), at most 10 000; never with object_sids.
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                        is_null:
                          type: boolean
                        contains:
                          type: string
                          minLength: 1
                        not_contains:
                          type: string
                          minLength: 1
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        starts_with:
                          type: string
                          minLength: 1
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Ad-hoc filter AST over the tab (§4.18 atoms, depth <= 5); stored resolved. Combinable with view_sid; XOR with object_sids. An empty/match-all filter form is rejected.
          additionalProperties: false
          description: "REQUIRED for enrich | export | bulk, forbidden for import (422). Exactly one form: object_sids XOR view_sid/filter."
        params:
          type: object
          properties:
            force_rerun:
              type: boolean
              description: "type=enrich: also re-queue done cells (explicit re-charge consent - §4.6). Default false."
            cells:
              type: string
              enum:
                - not_run
                - error
              description: "type=enrich: run only the cells that have not run (not_run) or only the error cells (error); omit for every cell but the done ones. Pass the same value to the estimate."
            format:
              type: string
              enum:
                - csv
              description: "type=export: CSV to S3 → file_url. Alternative to write_tool_sid."
            write_tool_sid:
              type: string
              maxLength: 64
              description: "type=export: push rows to an external tool via this gtm-api write tool (external sid). Alternative to format."
            data_source_sid:
              type: string
              minLength: 18
              maxLength: 18
              pattern: ^ds_sc_
              description: "type=import (REQUIRED there): the data source whose items are batch-promoted."
            operation:
              type: string
              enum:
                - add_tags
                - remove_tags
                - replace_tags
                - set_field_value
                - delete_objects
                - add_to_workflow
                - cancel_from_workflows
                - move_to_playtable
              description: "type=bulk (REQUIRED there): the bulk edit op. Its payload keys ride alongside: tag_sids[] (add / remove / replace_tags), playtable_field_sid + value (set_field_value), workflow_sid (add_to_workflow), target playtable (move_to_playtable); checked per op."
          description: 'Type-specific params, snapshotted into params_snapshot: enrich {force_rerun?, cells?}; export {format:"csv"} or {write_tool_sid}; import {data_source_sid}; bulk {operation, …op payload}.'
        max_budget:
          type: number
          nullable: true
          description: "Decimal credits - enrich only: hard per-run spend cap; the budget guard cancels the run when exhausted (reason=budget_exhausted). Omit/null = uncapped. Base it on the estimate cost range."
      required:
        - playtable_sid
        - object_type
        - type
    CreatePlaytableRunResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            type:
              type: string
              enum:
                - enrich
                - export
                - import
                - bulk
            field_sids:
              type: array
              nullable: true
              items:
                type: string
            scope:
              type: object
              nullable: true
              properties:
                object_sids:
                  type: array
                  nullable: true
                  items:
                    type: string
                view_sid:
                  type: string
                  nullable: true
                filter:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: "Filter AST: and/or/not/any nodes (depth <= 5, root counts) over {field, op} leaves; op = >=1 of the §4.18 atoms; atoms AND."
              required:
                - object_sids
                - view_sid
                - filter
            params_snapshot:
              type: object
              nullable: true
              additionalProperties: {}
            max_budget:
              type: number
              nullable: true
            estimated_cost:
              type: number
              nullable: true
            file_url:
              type: string
              nullable: true
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            finished_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - type
            - field_sids
            - scope
            - params_snapshot
            - max_budget
            - estimated_cost
            - file_url
            - created_by
            - created_at
            - finished_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreatePlaytableViewRequest:
      type: object
      description: Request body of `create_playtable_view`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: people | company - which tab of the table; immutable after create.
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: View name; dedup key with (playtable_sid, object_type).
        columns:
          type: array
          items:
            type: object
            properties:
              column_type:
                type: string
                enum:
                  - group
                  - field
                  - field_group
                description: "'field' = custom field of the table (column_value = pt_fd_ sid); 'group' = built-in attribute group."
              column_value:
                type: string
                nullable: true
                minLength: 1
                description: "For 'field': pt_fd_ sid of a field on the SAME playtable + object_type (422 otherwise). For 'group': attribute-group key. Absent or null for 'field_group' (the band carries column_values instead)."
              column_values:
                type: array
                nullable: true
                items:
                  type: object
                  properties:
                    column_value:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^pt_fd_
                      description: "A field of the band: pt_fd_ sid on the SAME playtable + object_type."
                    width:
                      type: integer
                      minimum: 40
                      maximum: 1000
                      description: Member column width in px, 40..1000. Default 200.
                    is_visible:
                      type: boolean
                      description: Default true.
                  required:
                    - column_value
                  additionalProperties: false
                minItems: 2
                maxItems: 20
                description: "'field_group' only (null elsewhere): the band's members, 2..20 fields in grid order (a band is one block in the header reorder)."
              is_collapsed:
                type: boolean
                nullable: true
                description: "'field_group' only (null elsewhere): the band folded to its tag. Default false."
              column_name:
                type: string
                nullable: true
                maxLength: 255
                description: Header label override; omit or null = catalog / field name.
              is_pinned:
                type: boolean
                description: Pin to the left grid edge. Default false.
              width:
                type: integer
                minimum: 40
                maximum: 1000
                description: Column width in px, 40..1000. Default 200.
              is_visible:
                type: boolean
                description: Default true; hidden columns keep their slot and order.
            required:
              - column_type
            additionalProperties: false
          description: Ordered left→right. Default [] = base-attribute catalog fallback.
        sort:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                minLength: 1
                maxLength: 255
                description: Built-in object column ("created_at", "full_name") or "record.<slug>"; resolved against the view object_type.
              direction:
                type: string
                enum:
                  - asc
                  - desc
                description: "'asc' | 'desc'."
            required:
              - field
              - direction
            additionalProperties: false
          maxItems: 3
          description: Max 3 entries, applied in array order. Default [].
        filter:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar equality. eq: null is rejected - use is_null."
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar inequality. ne: null is rejected - use is_null."
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value in list, 1..100 scalars.
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value not in list, 1..100 scalars.
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Greater than; string operand = ISO 8601 datetime.
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                      description: ">= bound; pair with lte in the SAME op for a range."
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Less than; string operand = ISO 8601 datetime.
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                      description: <= bound; pair with gte in the SAME op for a range.
                    is_null:
                      type: boolean
                      description: true = absent-or-null; false = present and non-null.
                    contains:
                      type: string
                      minLength: 1
                      description: Case-insensitive substring match.
                    not_contains:
                      type: string
                      minLength: 1
                      description: Negated case-insensitive substring match.
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when ANY is a ci substring.
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when NONE is a ci substring.
                    starts_with:
                      type: string
                      minLength: 1
                      description: Case-insensitive prefix match.
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
            - {}
          description: Filter AST (and/or/not/any nodes over {field, op} leaves, §4.18 atoms) selecting the rows the view targets. Default null = whole tab. Depth <= 5.
      required:
        - playtable_sid
        - object_type
        - name
    CreatePlaytableViewResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: View sid (pt_vw_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            playtable_sid:
              type: string
              description: Owner playtable (pt_tb_…).
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object tab the view lenses: people | company. Fixed at create."
            name:
              type: string
              description: View name; unique per (playtable, object_type) among live rows.
            columns:
              type: array
              items:
                type: object
                properties:
                  column_type:
                    type: string
                    enum:
                      - group
                      - field
                      - field_group
                    description: "'field' = custom field of the table; 'group' = built-in attribute group of the object."
                  column_value:
                    type: string
                    nullable: true
                    description: "For 'field': pt_fd_ sid of the custom field. For 'group': built-in attribute-group key of the object_type. null for 'field_group'."
                  column_values:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        column_value:
                          type: string
                        width:
                          type: integer
                        is_visible:
                          type: boolean
                      required:
                        - column_value
                        - width
                        - is_visible
                    description: "'field_group' only: the band's member fields in grid order."
                  is_collapsed:
                    type: boolean
                    nullable: true
                    description: "'field_group' only: the band folded to its tag."
                  column_name:
                    type: string
                    nullable: true
                    description: Header label override; null = catalog / field name.
                  is_pinned:
                    type: boolean
                    description: Pinned to the left edge of the grid.
                  width:
                    type: number
                    description: Column width in px (40..1000).
                  is_visible:
                    type: boolean
                    description: Hidden columns keep their slot and order.
                required:
                  - column_type
                  - column_value
                  - column_name
                  - is_pinned
                  - width
                  - is_visible
              description: Ordered left→right; [] = base-attribute catalog fallback.
            sort:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: Built-in object column ("created_at", "full_name") or "record.<slug>" custom-field reference.
                  direction:
                    type: string
                    enum:
                      - asc
                      - desc
                    description: "'asc' | 'desc'."
                required:
                  - field
                  - direction
              description: Applied in array order; max 3 entries.
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Stored filter AST (§4.18-atom tree); null = whole tab.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the view (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the view; null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - columns
            - sort
            - filter
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreateStoplistEntryRequest:
      type: object
      description: Request body of `create_stoplist_entry`.
      properties:
        identifier_type:
          type: string
          enum:
            - ln_member_id
            - email
            - domain
            - ln_nickname
            - company_ln_nickname
          description: "The kind of ALL values in the call: ln_member_id (digits, or a profile, Sales Navigator or Recruiter URN, bare or in a URL), email, domain (the company and everyone by email domain), ln_nickname (profile slug/URL), company_ln_nickname (page slug/URL)."
        values:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 511
          minItems: 1
          maxItems: 500
          description: "1..500 identifiers, normalized server-side: ln_member_id to the base-10 id (a known URN decodes, a slug is a per-index 422); email trimmed and lowercased; domain to the bare host (punycode); a nickname kind to its lowercased slug (a URL reduces to it)."
        source:
          type: string
          enum:
            - csv_import
          description: "Say the batch was read out of a file: csv_import. Omit it for a typed or pasted list (the server stamps manual, or api for an API-token actor). The only value a caller may name; it changes how rows read back in search and counts, never how values match."
      required:
        - identifier_type
        - values
    CreateStoplistEntryResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Stoplist entry sid (sl_sl_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  identifier_type:
                    type: string
                    enum:
                      - ln_member_id
                      - email
                      - domain
                      - ln_nickname
                      - company_ln_nickname
                    description: "What kind of identifier this row blocks: ln_member_id | email | domain | ln_nickname | company_ln_nickname."
                  value:
                    type: string
                    description: "NORMALIZED identifier: the member id as base-10 digits (698599037), lowercase email, bare hostname (acme.com), or a lowercased vanity slug (janecooper, acme-corp). Raw input is not stored, and a URL or a URN never is."
                  source:
                    type: string
                    enum:
                      - manual
                      - csv_import
                      - api
                      - unsubscribe
                      - complaint
                    description: "Write path: manual | csv_import | api | unsubscribe. Stamped by the server; csv_import is the one value a user actor may name on create."
                  data_source_sid:
                    type: string
                    nullable: true
                    description: Provenance of a row the retired csv_stoplist data source promoted before 2026-09-20 (ds_sc_…); null on every row written since, the csv_import ones included.
                  data_source_item_sid:
                    type: string
                    nullable: true
                    description: Provenance of the staged row that produced such an entry (ds_it_…); null on every row written since.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that created the entry (AccessIdentityValue).
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that un-stoplisted the entry; null while live.
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC; always equals created_at - rows have no update path.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live entry (soft delete).
                required:
                  - sid
                  - team_sid
                  - identifier_type
                  - value
                  - source
                  - data_source_sid
                  - data_source_item_sid
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              already_exists:
                type: boolean
                description: true = this normalized value was already live on the list; the existing row is returned as-is.
            required:
              - item
              - already_exists
          description: One element per distinct normalized value, in input order (in-batch duplicates collapse).
        created_count:
          type: integer
          minimum: 0
          description: New rows inserted by this call.
        already_listed_count:
          type: integer
          minimum: 0
          description: Values that were already live on the list (existing rows returned, nothing re-inserted).
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - items
        - created_count
        - already_listed_count
        - meta
    CreateTagRequest:
      type: object
      description: Request body of `create_tag`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Label text; the (team_sid, name) dedup key - compared case-insensitively against live tags, stored as entered.
        color:
          type: string
          nullable: true
          minLength: 7
          maxLength: 7
          pattern: ^#[0-9a-f]{6}$
          description: Chip color "#rrggbb", lowercase hex. Default null = client default palette.
      required:
        - name
    CreateTagResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: Tag sid (cr_tg_…) - the value objects store in tag_sids[].
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            name:
              type: string
              description: Label text, stored as entered (original casing); unique per team case-insensitively among live rows.
            color:
              type: string
              nullable: true
              description: Chip color "#rrggbb" (lowercase hex); null = client default palette.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the tag (AccessIdentityValue).
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - name
            - color
            - created_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreateWorkflowAttachmentUploadUrlRequest:
      type: object
      description: Request body of `create_workflow_attachment_upload_url`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: "The file name the recipient sees (1..255); default: the file name the PUT declares in Content-Disposition, else upload with the extension of its Content-Type."
    CreateWorkflowAttachmentUploadUrlResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            upload_url:
              type: string
              description: The signed URL to PUT the bytes to, used exactly as given (the signature covers the path and the query); one use, then gone.
            method:
              type: string
              enum:
                - PUT
            expires_at:
              type: string
              description: "ISO 8601 UTC: the link stops working here, 15 minutes after the mint; mint again after it."
            max_bytes:
              type: integer
              minimum: 0
              exclusiveMinimum: true
              description: The body cap in bytes (10 MB, the multipart rule); a larger PUT is 422 on file.
            content_types:
              type: array
              items:
                type: string
              description: "The Content-Type values the PUT accepts: the document, image and archive families of the multipart allow-list. The bytes are sniffed too, so a script declared as a PDF is 422."
          required:
            - upload_url
            - method
            - expires_at
            - max_bytes
            - content_types
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    CreateWorkflowRequest:
      type: object
      description: Request body of `create_workflow`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: "The home playtable (pt_tb_…): the people the workflow enrolls and the record columns its steps read."
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Campaign name; dedup natural key within the team - duplicate returns the existing row with already_exists:true.
        description:
          type: string
          nullable: true
          maxLength: 2000
          description: Free text about the campaign (max 2000).
        draft_steps:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    nullable: true
                    description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_message
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Message template (same namespaces as all templates).
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_inmail
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    nullable: true
                    maxLength: 200
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_visit_profile
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_endorse_skills
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  skills_count:
                    type: integer
                    minimum: 1
                    maximum: 10
                    description: Endorse the person's top N listed skills, 1..10.
                required:
                  - type
                  - skills_count
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_withdraw_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_like_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_comment_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  comment:
                    type: string
                    minLength: 1
                    maxLength: 1250
                    description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - comment
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - email_send
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    minLength: 1
                    maxLength: 255
                  body:
                    type: string
                    minLength: 1
                    maxLength: 100000
                    description: HTML body template.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                  email_field:
                    type: string
                    nullable: true
                    description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                  cc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal copy addresses.
                  bcc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal blind-copy addresses.
                  attachments:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^wf_at_
                        name:
                          type: string
                          minLength: 1
                          maxLength: 255
                      required:
                        - sid
                        - name
                      additionalProperties: false
                    maxItems: 5
                    description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                  reply_in_thread:
                    type: boolean
                    nullable: true
                  track_opens:
                    type: boolean
                    nullable: true
                  track_clicks:
                    type: boolean
                    nullable: true
                  unsubscribe_link:
                    type: boolean
                    nullable: true
                required:
                  - type
                  - subject
                  - body
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  for:
                    type: string
                    pattern: ^[1-9][0-9]*[mhd]$
                    description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                required:
                  - type
                  - for
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait_for_event
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  event:
                    type: string
                    enum:
                      - linkedin_connection_request_accepted
                      - email_opened
                      - email_link_clicked
                    description: Event observed via the activities ingest.
                  timeout:
                    type: object
                    properties:
                      after:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                      steps:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - after
                      - steps
                    additionalProperties: false
                    description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                required:
                  - type
                  - event
                  - timeout
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - condition
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption.
                        when:
                          type: object
                          additionalProperties: {}
                          description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - when
                        - steps
                      additionalProperties: false
                    minItems: 1
                    maxItems: 9
                    description: 1..9 branches, evaluated in order, first match wins.
                  else:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                required:
                  - type
                  - branches
                  - else
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ab_test
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption ("Variant A").
                        weight:
                          type: integer
                          minimum: 1
                          description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - weight
                        - steps
                      additionalProperties: false
                    minItems: 2
                    maxItems: 9
                    description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                required:
                  - type
                  - branches
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - end
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - api_call
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  method:
                    type: string
                    enum:
                      - GET
                      - POST
                      - PUT
                      - PATCH
                      - DELETE
                  url:
                    type: string
                    minLength: 1
                    maxLength: 2048
                    description: https-only (publish check); a template - variables may stand in the path and the query.
                  headers:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 1024
                  query:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 2048
                  body:
                    type: string
                    nullable: true
                    maxLength: 16000
                    description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                  provider_connection_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^in_cn_
                    description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                  timeout_secs:
                    type: integer
                    nullable: true
                    minimum: 1
                    maximum: 120
                  retry_on_error:
                    type: boolean
                    nullable: true
                  remove_empty_values:
                    type: boolean
                    nullable: true
                  output_key:
                    type: string
                    nullable: true
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                required:
                  - type
                  - method
                  - url
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ask_ai
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  prompt:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Same variable namespaces as message templates.
                  output_key:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                  preset_sid:
                    type: string
                    nullable: true
                    description: gtm-api preset for the AI call; null = team default.
                required:
                  - type
                  - prompt
                  - output_key
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - manual_task
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  title:
                    type: string
                    minLength: 1
                    maxLength: 255
                  instructions:
                    type: string
                    nullable: true
                    maxLength: 4000
                    description: Rendered into the human todo; the journey waits until the task is completed.
                required:
                  - type
                  - title
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - move_to_workflow
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  target_workflow_sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                  mode:
                    type: string
                    nullable: true
                    enum:
                      - from_start
                      - from_current
                    description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                required:
                  - type
                  - target_workflow_sid
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - add_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - remove_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - set_field
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  field_slug:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                  value:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - {}
                      - {}
                    description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                required:
                  - type
                  - field_slug
                  - value
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - change_sender
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  sender_profile_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                    description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                  rotation:
                    type: string
                    nullable: true
                    enum:
                      - fair
                      - random
                      - new_sender
                      - prior_engagement
                    description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                required:
                  - type
                additionalProperties: false
          description: Initial step document (chain-and-blocks; see the step schema). Default []. Omit step ids - server assigns and returns them.
        schedule:
          type: object
          nullable: true
          properties:
            timeblocks:
              type: array
              items:
                type: object
                properties:
                  dow:
                    type: integer
                    minimum: 0
                    maximum: 6
                    description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                  start_minute:
                    type: integer
                    minimum: 0
                    maximum: 1439
                    description: "Minutes from local midnight (legacy key: min)."
                  end_minute:
                    type: integer
                    minimum: 1
                    maximum: 1440
                    description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                required:
                  - dow
                  - start_minute
                  - end_minute
                additionalProperties: false
              minItems: 1
              maxItems: 7
              description: 1..7 blocks; at most one block per day-of-week in v1 (server-validated).
            timezone:
              type: string
              minLength: 1
              maxLength: 64
              description: IANA tz name, e.g. "Europe/Lisbon" - base timezone for the blocks.
            use_people_timezone:
              type: boolean
              description: Default false - resolve blocks in the person's timezone when known, fall back to `timezone` (legacy use_lead_timezone).
          required:
            - timeblocks
            - timezone
          additionalProperties: false
          description: The campaign's sending windows (per-dow minute blocks + timezone). Default null = any time; gtm-api's per-account limits still pace.
        on_reply:
          type: string
          enum:
            - autopilot
            - copilot
            - stop
            - continue
          description: "Default copilot. What a reply does: autopilot | copilot pause the records and hand the thread to the AI SDR (it answers, or drafts for approval); stop pauses and leaves the thread to a human; continue keeps sending."
        sender_profile_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_sp_
          description: Sender pool (ub_sp_…, existence-checked). Default []. Publish requires >=1 when the graph has send steps.
        rotation_strategy:
          type: string
          enum:
            - fair
            - random
            - new_sender
            - prior_engagement
          description: Default 'fair'. Sender pinned per record at enrollment.
        priority:
          type: integer
          minimum: 1
          maximum: 3
          description: Cross-workflow task scheduling weight per sender, 1..3; default 2.
        agent_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_ag_
          description: The AI SDR for the threads this workflow starts (ub_ag_…, from search_agents on unibox); left out or null = its home table's pick, else the team's default.
      required:
        - playtable_sid
        - name
    CreateWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    CreateWorkflowSourceRequest:
      type: object
      description: Request body of `create_workflow_source`.
      properties:
        workflow_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^wf_wf_
          description: Parent campaign (wf_wf_…) - must exist, be non-deleted and not archived (409 conflict).
        type:
          type: string
          enum:
            - view
            - filter
            - manual
            - event
          description: view | filter | manual - picks the XOR payload (view ⇒ view_sid; filter ⇒ filter; manual ⇒ optional people_sids). Immutable after create.
        event:
          type: string
          nullable: true
          enum:
            - linkedin_connection_request_accepted
            - linkedin_message_replied
            - linkedin_inmail_replied
            - email_replied
            - email_opened
            - email_link_clicked
            - linkedin_invitation_received
            - linkedin_followed
            - website_visited
            - website_key_page_visited
            - website_form_submitted
          description: "REQUIRED for type=event, forbidden otherwise (422): the activity type whose occurrence enrolls the person (activities.md); explicit null is the same as omitted."
        name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: Optional label ("Conference batch"); omit or null = unlabeled.
        view_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^pt_vw_
          description: REQUIRED for type=view, forbidden otherwise (422); explicit null ≈ omitted under the XOR server-rule. Playtable view (pt_vw_…) whose live membership is the audience; validated existing + non-deleted.
        filter:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar equality. eq: null is rejected - use is_null."
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar inequality. ne: null is rejected - use is_null."
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value in list, 1..100 scalars.
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value not in list, 1..100 scalars.
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Greater than; string operand = ISO 8601 datetime.
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                      description: ">= bound; pair with lte in the SAME op for a range."
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Less than; string operand = ISO 8601 datetime.
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                      description: <= bound; pair with gte in the SAME op for a range.
                    is_null:
                      type: boolean
                      description: true = absent-or-null; false = present and non-null.
                    contains:
                      type: string
                      minLength: 1
                      description: Case-insensitive substring match.
                    not_contains:
                      type: string
                      minLength: 1
                      description: Negated case-insensitive substring match.
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when ANY is a ci substring.
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when NONE is a ci substring.
                    starts_with:
                      type: string
                      minLength: 1
                      description: Case-insensitive prefix match.
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
            - {}
          description: REQUIRED for type=filter, forbidden otherwise (422). Inline audience AST over the team's people (and/or/not/any over {field, op} leaves, §4.18 atoms, depth ≤ 5); record.<slug> resolves per person's playtable at evaluation (missing ⇒ false).
        people_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_pp_
          minItems: 1
          maxItems: 500
          description: "type=manual only (forbidden otherwise): 1..500 cr_pp_ sids enrolled synchronously through the same entry decisions as add-people; requires a published workflow version (422 invalid_transition)."
        auto_add:
          type: boolean
          description: Default false. view/filter only - true enqueues an immediate first sweep; true on manual → 422.
        active_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "Enrollment throttle (default null = unlimited): max simultaneous in-flight records from this source. Over-cap candidates WAIT (blocked_limit_count), not rejected."
        coworkers_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "Enrollment throttle (default null = unlimited): max simultaneous in-flight records from this source per company."
      required:
        - workflow_sid
        - type
    CreateWorkflowSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - create
        item:
          type: object
          properties:
            sid:
              type: string
              description: Source sid (wf_sr_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              description: "[ro] Parent workflow (wf_wf_…) - see ./workflows.md."
            view_sid:
              type: string
              nullable: true
              description: Audience view (pt_vw_…) - set on type=view only, null otherwise; repointable via update - see ./playtable_views.md.
            name:
              type: string
              nullable: true
              description: Optional label ("Conference batch"), max 255; null = unlabeled.
            type:
              type: string
              enum:
                - view
                - filter
                - manual
                - event
              description: "[ro] view = playtable view membership | filter = inline AST | manual = hand-picked people. Immutable - repoint = delete + create."
            event:
              type: string
              nullable: true
              enum:
                - linkedin_connection_request_accepted
                - linkedin_message_replied
                - linkedin_inmail_replied
                - email_replied
                - email_opened
                - email_link_clicked
                - linkedin_invitation_received
                - linkedin_followed
                - website_visited
                - website_key_page_visited
                - website_form_submitted
              description: "type=event only: the activity type that enrolls a person (required at create for an event source, 422 otherwise); null on the other types."
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Inline audience AST (type=filter only, null otherwise) over the team's people; ES resolves membership, record.<slug> leaves resolve per person's playtable (missing slug ⇒ false).
            auto_add:
              type: boolean
              description: "Poller toggle (view/filter): true = every cycle (~10 min) ES lists current audience members and MySQL decides entry; false = dormant pointer. Always false on manual."
            active_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight (non-terminal) records entered via THIS source; null = unlimited. Reached => new candidates wait (blocked_limit_count).
            coworkers_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight records from THIS source for people of the SAME company; null = unlimited. Reached for a company => that company's candidates wait.
            entered_count:
              type: integer
              minimum: 0
              description: "[ro] Total workflow_records ever inserted via this source - monotonic on ALL types (cache of the entered_via_source_sid count)."
            blocked_stoplisted_count:
              type: integer
              minimum: 0
              description: "[ro] Stoplist entry blocks. view/filter: LIVE backlog gauge, recomputed each poll cycle over current audience members (un-stoplisted people drop out and enter); manual: cumulative per call."
            blocked_duplicate_in_workflow_count:
              type: integer
              minimum: 0
              description: "[ro] Poller-only: candidates skipped as already enrolled in this workflow via ANY source (auto_add never re-enters). view/filter: live gauge per poll cycle; ~0 on manual (add-people re-enters instead)."
            blocked_limit_count:
              type: integer
              minimum: 0
              description: "[ro] Candidates WAITING because active_limit / coworkers_limit is reached this cycle; they enter automatically once a slot frees. view/filter: live gauge; manual: cumulative per call."
            blocked_other_count:
              type: integer
              minimum: 0
              description: "[ro] Blocked as deleted/missing/otherwise ineligible people. view/filter: live gauge per poll cycle; manual: cumulative per call."
            last_evaluated_at:
              type: string
              nullable: true
              description: "[ro] Last poll cycle (view/filter) or last add-people / inline-create batch (manual); ISO 8601 UTC, null = never evaluated."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that attached the feed (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the feed (own verb or workflows.delete cascade); null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete - the poller gates on it).
          required:
            - sid
            - team_sid
            - workflow_sid
            - view_sid
            - name
            - type
            - filter
            - auto_add
            - active_limit
            - coworkers_limit
            - entered_count
            - blocked_stoplisted_count
            - blocked_duplicate_in_workflow_count
            - blocked_limit_count
            - blocked_other_count
            - last_evaluated_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        already_exists:
          type: boolean
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_exists
        - meta
    DeleteCompanyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeleteDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeleteNoteResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeletePersonResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeletePipelineStageResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeletePlayResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeletePlaytableFieldResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeletePlaytableResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeletePlaytableViewResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeleteResultPageResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeleteStoplistEntryResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeleteTagResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeleteWorkflowAttachmentResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DeleteWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        cascade:
          type: object
          nullable: true
          properties:
            summary:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  entity:
                    type: string
                  deleted:
                    type: integer
                  cancelled:
                    type: integer
                required:
                  - entity
                  - deleted
            recovery_available_until:
              type: string
              nullable: true
          required:
            - summary
            - details
            - recovery_available_until
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - cascade
        - meta
    DeleteWorkflowSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - delete
        item:
          type: object
          additionalProperties: {}
        already_deleted:
          type: boolean
        soft_deleted:
          type: boolean
        retained:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - already_deleted
        - soft_deleted
        - retained
        - meta
    DetachCompanyPlaytableRequest:
      type: object
      description: Request body of `detach_company_playtable`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: The table to remove the company from.
      required:
        - playtable_sid
    DetachCompanyPlaytableResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        result:
          type: object
          properties:
            detached:
              type: boolean
              description: false = the sid was not a member; nothing changed.
          required:
            - detached
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    DraftForActivityRequest:
      type: object
      description: Request body of `draft_for_activity`.
      properties:
        do:
          type: string
          enum:
            - comment
            - send_message
          description: "comment: on a post event only; send_message: a message to the person of any event."
        sender_profile_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: Checked to be one that can act; the words do not depend on it.
      required:
        - do
    DraftForActivityResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            text:
              type: string
              description: "The words: a comment the AI wrote from the whole post under the table's Engage with posts brief, or the moment's message (a birthday, a work anniversary, a job change) rendered for the person; an empty string when no writer covers the event."
          required:
            - text
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    EstimatePlayResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Play sid (pt_pl_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…).
            playtable_sid:
              type: string
              description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
            catalog_key:
              type: string
              nullable: true
              enum:
                - keep_fresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
                - find_people_empty
                - top_up_thin
                - top_up_silent
                - top_up_no_reply
                - top_up_exhausted
                - find_decision_maker
                - reengage_dormant
                - reach_untouched
              description: The playbook entry the row was born from; null = a play saved from a view's filter.
            name:
              type: string
              description: The play's name, 1..255.
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What the audience selects: people, or company (accounts)."
            action_type:
              type: string
              enum:
                - find_people
                - add_to_workflow
                - refresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
              description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
            action:
              anyOf:
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                    per_company_limit:
                      type: integer
                      nullable: true
                      description: People taken per account, 1..25; null = the whole first page.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                    workflow_source_sid:
                      type: string
                      nullable: true
                      description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                  required:
                    - workflow_sid
                    - workflow_source_sid
                - type: object
                  properties:
                    moments:
                      type: object
                      properties:
                        birthday:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        work_anniversary:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        job_change:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                      description: A switch per moment with its own Do under it; a kind absent is off.
                  required:
                    - moments
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - remove_from_workflows
                        - move_to_workflow
                      description: For a person in a workflow whose title or company moved.
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                  required:
                    - do
                    - workflow_sid
                - type: object
                  properties:
                    like:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        reaction:
                          type: string
                          enum:
                            - ai
                            - like
                            - celebrate
                            - support
                            - love
                            - insightful
                            - funny
                          description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                      required:
                        - "on"
                        - reaction
                    comment:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        brief:
                          type: string
                          nullable: true
                          maxLength: 2000
                          description: What the AI writes the comment from; required while on.
                      required:
                        - "on"
                        - brief
                    per_person_weekly_cap:
                      type: integer
                      minimum: 1
                      maximum: 14
                      description: At most this many acts a week per person.
                    sender_profile_sid:
                      type: string
                      nullable: true
                      description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                  required:
                    - like
                    - comment
                    - per_person_weekly_cap
                    - sender_profile_sid
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - add_to_workflow
                      description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: required when the Do is a workflow."
                    pages:
                      type: array
                      nullable: true
                      items:
                        type: string
                      description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                  required:
                    - do
                    - workflow_sid
                    - pages
                - type: object
                  properties: {}
                  description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
              description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
            audience:
              description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
            watch:
              type: object
              nullable: true
              properties:
                profile_days:
                  anyOf:
                    - type: number
                      enum:
                        - 7
                    - type: number
                      enum:
                        - 14
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                company_days:
                  anyOf:
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The company page every N days: 30 | 90; null = not watched."
                posts_days:
                  anyOf:
                    - type: number
                      enum:
                        - 1
                    - type: number
                      enum:
                        - 3
                    - type: number
                      enum:
                        - 7
                    - {}
                  description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                moments:
                  type: boolean
                  description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
              required:
                - profile_days
                - company_days
                - posts_days
                - moments
              description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
            cadence:
              type: string
              enum:
                - manual
                - daily
              description: "manual: runs on run_play; daily: runs by itself every day while enabled."
            mode:
              type: string
              enum:
                - ask_me
                - automatic
              description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
            enabled:
              type: boolean
              description: The switch of a daily play; a manual play is always false.
            enabled_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Who gave the consent (switched the play on).
            enabled_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when."
            daily_credit_limit:
              type: integer
              nullable: true
              description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
            last_run_at:
              type: string
              nullable: true
              description: ISO 8601 UTC.
            last_run_counts:
              type: object
              nullable: true
              properties:
                matched:
                  type: integer
                  minimum: 0
                  description: Rows the audience matched at the run (the tab's count under the filter).
                acted:
                  type: integer
                  minimum: 0
                  description: Accounts appended to the queue, or people entered or re-entered.
                skipped:
                  type: integer
                  minimum: 0
                  description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                credits:
                  type: integer
                  minimum: 0
                  description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
              required:
                - matched
                - acted
                - skipped
                - credits
              description: What the last run did; null before the first run.
            next_run_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live.
          required:
            - sid
            - team_sid
            - playtable_sid
            - catalog_key
            - name
            - object_type
            - action_type
            - action
            - watch
            - cadence
            - mode
            - enabled
            - enabled_by
            - enabled_at
            - daily_credit_limit
            - last_run_at
            - last_run_counts
            - next_run_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            matched:
              type: integer
              minimum: 0
              description: Rows the audience matched at the run (the tab's count under the filter).
            acted:
              type: integer
              minimum: 0
              description: Accounts appended to the queue, or people entered or re-entered.
            skipped:
              type: integer
              minimum: 0
              description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
            credits:
              type: integer
              minimum: 0
              description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
            ceiling_applies:
              type: boolean
              description: true when a daily_credit_limit bounds the run counted here.
            credits_month:
              type: number
              nullable: true
              description: "What the play costs a month over the audience: per kind, the rows times the reads a month at the cadence times the kind's price per row (the table's columns of the kind), and for Engage with posts the AI's comments at the weekly cap (2026-10-16); null when the play reads nothing on a cadence and writes no comment (2026-10-13)."
            credits_month_parts:
              type: array
              items:
                type: object
                properties:
                  kind:
                    type: string
                    description: profile, company or posts (a read the table can make), or ai_comment (Engage with posts' AI comments).
                  object_type:
                    type: string
                    description: "people or company: the tab the part runs over."
                  rows:
                    type: integer
                    minimum: 0
                    description: The rows of the audience the part runs over.
                  days:
                    type: integer
                    nullable: true
                    description: The cadence the count is at; null while the play does not read this kind on one (the count and the credits are 0 then).
                  count:
                    type: integer
                    minimum: 0
                    description: Reads, or comments, a month.
                  price:
                    type: number
                    description: Credits for one.
                  credits:
                    type: number
                    description: What the part comes to a month.
                required:
                  - kind
                  - object_type
                  - rows
                  - days
                  - count
                  - price
                  - credits
              description: 'The month part by part, so the number can be said whole: "59 people: about 253 profile reads at 5 each and 11 company page reads at 2 each". A kind the play does not use yet is listed at no cost with its rows and its price (2026-10-16).'
          required:
            - matched
            - acted
            - skipped
            - credits
            - ceiling_applies
            - credits_month
            - credits_month_parts
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    EstimatePlaytableFieldAiCostRequest:
      type: object
      description: Request body of `estimate_playtable_field_ai_cost`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "The grid the column sits on: people or company."
        payload:
          type: object
          properties:
            prompt:
              type: string
              minLength: 1
              maxLength: 8192
              description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
            model:
              type: string
              minLength: 1
              maxLength: 128
              description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
            output:
              type: string
              enum:
                - text
                - number
                - select
                - json
              description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
            options:
              type: array
              nullable: true
              items:
                type: string
              minItems: 1
              description: Required (min 1) when output=select; null otherwise.
            output_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  path:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 128
                    description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                required:
                  - path
                  - target
              maxItems: 20
              description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
            web_search:
              type: boolean
              description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
          required:
            - prompt
            - model
            - output
            - options
            - output_mapping
          description: The drawer's live draft (prompt, model, output, options, web_search), validated exactly like create_playtable_field's. The prompt is rendered on the rows, so a {{record.<slug>}} that pulls a whole enrichment cell is priced at its size.
      required:
        - playtable_sid
        - object_type
        - payload
    EstimatePlaytableFieldAiCostResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            rows_sampled:
              type: integer
              minimum: 0
              description: Rows the prompt was rendered on (the grid's first rows, up to 20); 0 when the grid has none and the prompt's own words were read.
            rows_skipped:
              type: integer
              minimum: 0
              description: "Rows of the sample the run would skip for an empty context (every variable resolved to nothing): free."
            rows_total:
              type: integer
              minimum: 0
              description: Rows of the grid the sample stands for.
            tokens_in:
              type: object
              properties:
                min:
                  type: integer
                  minimum: 0
                avg:
                  type: integer
                  minimum: 0
                max:
                  type: integer
                  minimum: 0
              required:
                - min
                - avg
                - max
              description: The rendered prompt with the answer instruction, in tokens by the platform's estimate (2.6 bytes a token).
            tokens_out_expected:
              type: integer
              minimum: 0
              description: "The answer a typical row gets: the response, its reasoning and a confidence word."
            prices:
              type: array
              items:
                type: object
                properties:
                  provider:
                    type: string
                  model:
                    type: string
                  name:
                    type: string
                  default:
                    type: boolean
                    description: The model payload.model auto resolves to.
                  web_search:
                    type: boolean
                    description: The model can run web research.
                  price_min:
                    type: number
                    minimum: 0
                    description: "Credits: the smallest sampled row with a typical answer."
                  price_expected:
                    type: number
                    minimum: 0
                    description: "Credits: the average row with a typical answer, what one row is expected to cost."
                  price_max:
                    type: number
                    minimum: 0
                    description: "Credits: the largest sampled row with a typical answer; min to max is the range a drawer shows."
                  price_cap:
                    type: number
                    minimum: 0
                    description: "Credits: the largest row with the model's whole output cap, what a run's max_budget is set from."
                  price_with_web_search_min:
                    type: number
                    nullable: true
                    description: The same four with web research on (the search tool's overhead on every prompt, then none, one, one and the cap of searches); null when the model cannot search.
                  price_with_web_search_expected:
                    type: number
                    nullable: true
                  price_with_web_search_max:
                    type: number
                    nullable: true
                  price_with_web_search_cap:
                    type: number
                    nullable: true
                required:
                  - provider
                  - model
                  - name
                  - default
                  - web_search
                  - price_min
                  - price_expected
                  - price_max
                  - price_cap
                  - price_with_web_search_min
                  - price_with_web_search_expected
                  - price_with_web_search_max
                  - price_with_web_search_cap
              description: One price per model of the catalog; pick payload.model's (or the default for auto).
          required:
            - rows_sampled
            - rows_skipped
            - rows_total
            - tokens_in
            - tokens_out_expected
            - prices
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    EstimatePlaytableFieldBackfillRequest:
      type: object
      description: Request body of `estimate_playtable_field_backfill`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: The table (pt_tb_…); 404 not_found outside the caller's team.
        object_type:
          type: string
          enum:
            - people
            - company
          description: "The grid the column sits on: people or company."
        columns:
          type: integer
          minimum: 1
          maximum: 200
          description: Columns the save queues at once (a pass computes them in one walk, so the seconds add up). Default 1.
      required:
        - playtable_sid
        - object_type
    EstimatePlaytableFieldBackfillResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            rows:
              type: integer
              minimum: 0
              description: The rows of the grid the pass walks.
            columns:
              type: integer
              minimum: 0
              exclusiveMinimum: true
              description: As asked.
            seconds_expected:
              type: integer
              minimum: 0
              description: "ceil(rows x columns / cells_a_second): one worker's wall time."
            cells_a_second:
              type: integer
              minimum: 0
              exclusiveMinimum: true
              description: The rate used (playtables.runs.estimate_cells_per_second).
            confirm_above_seconds:
              type: integer
              minimum: 0
              description: The drawer asks the person first above this many seconds; 0 means never.
            needs_confirm:
              type: boolean
              description: seconds_expected > confirm_above_seconds.
          required:
            - rows
            - columns
            - seconds_expected
            - cells_a_second
            - confirm_above_seconds
            - needs_confirm
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    EstimatePlaytableRunRequest:
      type: object
      description: Request body of `estimate_playtable_run`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Parent playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Which tab the run would target: people | company."
        type:
          type: string
          enum:
            - enrich
          description: "The type of the run this prices: enrich, the one paid type, the same word create_playtable_run takes (export, import and bulk have nothing to estimate). Optional; any other word is a 422 here, before the create."
        field_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_fd_
          minItems: 1
          maxItems: 20
          description: The fields that would run (pt_fd_…, 1..20; action columns only).
        scope:
          type: object
          properties:
            object_sids:
              type: array
              nullable: true
              items:
                type: string
                minLength: 18
                maxLength: 18
              minItems: 1
              description: "Explicit targets (cr_pp_… / cr_co_… of the run object_type), min 1, max 10 000 (a wider selection is a view/filter, optionally with exclude_object_sids). Exactly one scope form: XOR with view_sid/filter - both or neither → 422."
            view_sid:
              type: string
              nullable: true
              minLength: 18
              maxLength: 18
              pattern: ^pt_vw_
              description: Saved view (pt_vw_…) - its filter AST is snapshotted into the run at create; later view edits do not retarget. Combinable with filter; XOR with object_sids.
            exclude_object_sids:
              type: array
              nullable: true
              items:
                type: string
                minLength: 18
                maxLength: 18
              maxItems: 10000
              description: Rows of the view/filter form to leave out (select all minus the unticked rows), at most 10 000; never with object_sids.
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                        is_null:
                          type: boolean
                        contains:
                          type: string
                          minLength: 1
                        not_contains:
                          type: string
                          minLength: 1
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        starts_with:
                          type: string
                          minLength: 1
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Ad-hoc filter AST over the tab (§4.18 atoms, depth <= 5); stored resolved. Combinable with view_sid; XOR with object_sids. An empty/match-all filter form is rejected.
          additionalProperties: false
          description: "Same XOR rule as create: object_sids XOR view_sid/filter."
        force_rerun:
          type: boolean
          description: Default false - count done cells as re-runnable (they would be re-charged).
        cells:
          type: string
          enum:
            - not_run
            - error
          description: Price only the cells that have not run (not_run) or only the error cells (error); the same selection as params.cells on create.
      required:
        - playtable_sid
        - object_type
        - field_sids
        - scope
    EstimatePlaytableRunResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            rows_matched:
              type: number
              description: Scope size (ES count; approximate by design - the worker re-checks per cell).
            cost_min:
              type: number
              description: Credits if every row succeeds on the cheapest step.
            cost_max:
              type: number
              description: Credits if every row walks the full waterfall at max prices.
            cost_expected:
              type: number
              description: Registry expected-price path × rows_to_run.
            currency:
              type: string
              enum:
                - credits
            priced_at:
              type: string
              description: ISO 8601 UTC - registry price snapshot time.
            fields:
              type: array
              items:
                type: object
                properties:
                  playtable_field_sid:
                    type: string
                  rows_to_run:
                    type: number
                    description: Rows the run would actually enqueue (run_condition prefilter; skips done unless force_rerun, narrowed by cells).
                  cost_min:
                    type: number
                  cost_max:
                    type: number
                  cost_expected:
                    type: number
                  steps:
                    type: array
                    items:
                      type: object
                      properties:
                        tool_sid:
                          type: string
                          description: gtm-api tool at this waterfall step (external sid).
                        price_min:
                          type: number
                          description: Registry min price per row, credits.
                        price_max:
                          type: number
                          description: Registry max price per row, credits.
                      required:
                        - tool_sid
                        - price_min
                        - price_max
                    description: Materialized waterfall with the registry price range per step.
                required:
                  - playtable_field_sid
                  - rows_to_run
                  - cost_min
                  - cost_max
                  - cost_expected
                  - steps
              description: Per-field, per-step breakdown.
          required:
            - rows_matched
            - cost_min
            - cost_max
            - cost_expected
            - currency
            - priced_at
            - fields
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    EstimateSemanticIndexRequest:
      type: object
      description: Request body of `estimate_semantic_index`.
      properties:
        provider:
          type: string
          minLength: 1
          maxLength: 64
          description: The embed provider the knob would carry, e.g. "openai". A pairing the platform catalog does not list is 422 relation_not_found, as on update.
        model:
          type: string
          minLength: 1
          maxLength: 128
          description: 'The embed model, e.g. "text-embedding-3-small". An unreachable catalog is 503 service_unavailable: without the rate there is no honest number.'
      required:
        - provider
        - model
    EstimateSemanticIndexResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            cells_filled:
              type: integer
              minimum: 0
              description: Cells holding text the index embeds (valid, non-empty after trim).
            cells_to_embed:
              type: integer
              minimum: 0
              description: Of them, the ones a backfill with THIS model pays for now; text already embedded with the same model is free (content hash).
            cost_expected:
              type: number
              minimum: 0
              description: Credits the backfill costs now.
            cost_per_value_min:
              type: number
              minimum: 0
              description: "Credits one new or edited value costs later, at least: its own call, one unit, which covers any value up to about 1000 tokens."
            cost_per_value_max:
              type: number
              minimum: 0
              description: "Credits one later value costs at most: a value at the index's 8,000-character cap, written in this column's script."
            currency:
              type: string
              enum:
                - credits
            sampled:
              type: boolean
              description: "true when the column held more than 5,000 cells: counted and priced on the first 5,000, extrapolated to the rest."
            priced_at:
              type: string
              description: ISO 8601 UTC instant of the pricing.
          required:
            - cells_filled
            - cells_to_embed
            - cost_expected
            - cost_per_value_min
            - cost_per_value_max
            - currency
            - sampled
            - priced_at
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ExitWorkflowRecordRequest:
      type: object
      description: Request body of `exit_workflow_record`.
      properties:
        reason:
          type: string
          maxLength: 512
          description: Free-form; stored in the workflow-records.exited event payload only - not on the row.
    ExitWorkflowRecordResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            workflow_sid:
              type: string
              description: wf_wf_… owning workflow; DB-UNIQUE together with people_sid - one row per (workflow, person) pair, forever - see ./workflows.md.
            workflow_version_sid:
              type: string
              description: wf_vr_… version pinned at enrollment - the record executes that step graph even after newer publishes - see ./workflow_versions.md.
            people_sid:
              type: string
              description: cr_pp_… the enrolled person; second half of the DB-UNIQUE pair - see ./people.md.
            entered_via_source_sid:
              type: string
              description: wf_sr_… entry point that produced the row (immutable audit) - see ./workflow_sources.md.
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… sender pinned at enrollment; null when the version has no send steps; re-resolved at next dispatch if the profile is deleted - see ./sender_profiles.md.
            current_step_id:
              type: number
              description: Small int step id inside the pinned version steps JSON (server-assigned, immutable, never reused) - a JSON node pointer, not a sid or row.
            status:
              type: string
              enum:
                - waiting_limit
                - blocked
                - active
                - waiting
                - paused_on_reply
                - paused_manual
                - paused_blocked
                - failed
                - completed
                - exited
            entered_at:
              type: string
              nullable: true
            touches_done:
              type: integer
              minimum: 0
            rotations_done:
              type: integer
              minimum: 0
            error_code:
              type: string
              nullable: true
              description: Machine code of the last failure, from the failing task result (max 64).
            error_message:
              type: string
              nullable: true
              description: Human-readable detail of the last failure (max 1024).
            last_touch_at:
              type: string
              description: ISO 8601 UTC - last step advance or status change; the staleness clock.
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once when status enters a terminal state; null while live.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - people_sid
            - entered_via_source_sid
            - sender_profile_sid
            - current_step_id
            - status
            - entered_at
            - touches_done
            - rotations_done
            - error_code
            - error_message
            - last_touch_at
            - finished_at
            - created_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_exited:
              type: boolean
              description: true = idempotent no-op (the record was already terminal-exited).
            cancelled_tasks_count:
              type: integer
              minimum: 0
              description: pending/scheduled tasks of this record cancelled in the same transaction (bulk → counts per §4.12a; rows not embedded).
          required:
            - already_exited
            - cancelled_tasks_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    GeneratePlaytableFieldConditionRequest:
      type: object
      description: Request body of `generate_playtable_field_condition`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Which rows the rule is about, people or company: the tab the draft column belongs to."
        nl_condition:
          type: string
          minLength: 2
          maxLength: 2048
          description: The rule in words ("only companies with a website and nobody found yet"). The prompt gets the tab's columns and the built-in attributes, never row data; a column the tab lacks cannot be used.
      required:
        - playtable_sid
        - object_type
        - nl_condition
    GeneratePlaytableFieldConditionResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            run_condition:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                        is_null:
                          type: boolean
                        contains:
                          type: string
                          minLength: 1
                        not_contains:
                          type: string
                          minLength: 1
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        starts_with:
                          type: string
                          minLength: 1
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: The validated AST, ready for config.run_condition; null when error_code says why there is none.
            error_code:
              type: string
              nullable: true
              description: null on success. A lane code (integrations_unconfigured, network_error, ...) when the model call failed; generation_unparseable; condition_not_expressible (the model refused the rule); condition_invalid (the JSON failed the save-time gate).
            error_message:
              type: string
              nullable: true
              description: The provider's own text on a lane code, the model's one-line reason on condition_not_expressible; null otherwise.
            credits_charged:
              type: number
              minimum: 0
              description: What the one llm.generate call cost, in credits (0 when nothing was called).
          required:
            - run_condition
            - error_code
            - error_message
            - credits_charged
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    GetActivitiesMetricsRequest:
      type: object
      description: Request body of `get_activities_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ac_
                  description: Activity sid (cr_ac_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ac_
                    description: Activity sid (cr_ac_…).
              additionalProperties: false
              description: Activity sid(s), cr_ac_ prefix (prefix-validated).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
              additionalProperties: false
              description: person | company.
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Timeline scope - cr_pp_/cr_co_ sid(s); `in` for company roll-ups (person sids from ./people.md search).
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object
                    - workflow
                    - ai_agent
                    - linkedin
                    - email
                    - website
                    - other
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
              additionalProperties: false
              description: Type-group filter - cheaper than a long type.in list.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object_created
                    - object_updated
                    - object_deleted
                    - object_playtable_changed
                    - object_pipeline_stage_changed
                    - tags_added
                    - tags_removed
                    - workflow_added
                    - workflow_restarted
                    - workflow_cancelled
                    - workflow_finished
                    - workflow_failed
                    - ai_agent_status_changed
                    - ai_agent_fact_saved
                    - linkedin_connection_request_sent
                    - linkedin_connection_request_accepted
                    - linkedin_connection_request_withdrawn
                    - linkedin_blocked
                    - linkedin_message_sent
                    - linkedin_inmail_sent
                    - linkedin_message_replied
                    - linkedin_inmail_replied
                    - linkedin_message_opened
                    - linkedin_link_clicked
                    - linkedin_post_liked
                    - linkedin_post_commented
                    - linkedin_profile_visited
                    - linkedin_skills_endorsed
                    - linkedin_invitation_received
                    - linkedin_invitation_accepted
                    - linkedin_invitation_ignored
                    - linkedin_invitation_expired
                    - linkedin_connection_removed
                    - linkedin_followed
                    - linkedin_message_reacted
                    - linkedin_message_deleted
                    - linkedin_profile_viewed_us
                    - email_sent
                    - email_replied
                    - email_opened
                    - email_bounced
                    - email_link_clicked
                    - email_unsubscribed
                    - email_complained
                    - website_visited
                    - website_key_page_visited
                    - website_form_submitted
                    - website_event
                    - manual_task_completed
                    - note_left
                    - object_enriched
                    - object_data_changed
                    - linkedin_job_changed
                    - linkedin_post_published
                    - linkedin_birthday
                    - linkedin_work_anniversary
                    - linkedin_profile_followed
                    - linkedin_post_engaged
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
              additionalProperties: false
              description: Exact fact kinds.
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                is_null:
                  type: boolean
              additionalProperties: false
              description: wf_wf_ sid(s); is_null:true = facts outside any workflow.
            workflow_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
                is_null:
                  type: boolean
              additionalProperties: false
              description: The step id (within its workflow) the fact was produced by; is_null:true = facts outside any step.
            occurred_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object. Ignored on metrics - period owns the window.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
              additionalProperties: false
              description: "A table's feed: the facts of its live people and the website facts of the accounts they work at. eq only."
            play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: "What plays caused: the people their find_people sources created (object_created) and the journeys their workflow sources began or started over (workflow_added, workflow_restarted). A non-empty in only."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                  minItems: 1
                is_null:
                  type: boolean
              additionalProperties: false
              description: The sender profile a fact came through (ub_sp_). A fact no sender profile made (website, CRM, workflow) never passes this leaf, leave it out to keep them; is_null true keeps only such facts. One of eq, non-empty in or is_null; another prefix is a 422.
            act_state:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting
                    - done
                    - none
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting
                      - done
                      - none
              additionalProperties: false
              description: waiting = a task waits on the event (a draft, a question, a failed act); done = handled, nothing waiting (a task of any status names it, an act left its fact, a wait woke); none = nothing touched it, never a kind no play handles. eq or non-empty in.
            acted_play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: The events those plays acted on, by a task or a fact naming the event. A non-empty in only.
            involved_sender_profile_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
              additionalProperties: false
              description: The facts stamped with those sender profiles, and the events a task or a fact of theirs answers (a post carries no sender profile; the comment drafted on it does). A non-empty in only.
            involved_workflow_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: "One campaign's events: the events of the people who hold or held a record of those workflows (a left journey counts) and the facts those workflows wrote. Wider than workflow_sid, which keeps the workflow's own facts alone. A non-empty in only."
            act_do:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - like
                      - comment
                      - send_message
                      - ask
                      - add_to_workflow
              additionalProperties: false
              description: "What an act did about the event, by a DONE task's act.do or the act's fact: like = linkedin_post_liked, comment = linkedin_post_commented, send_message = linkedin_message_sent; ask and add_to_workflow by the task alone. A non-empty in only."
            field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: "The facts a column's pull wrote, read off payload.field_sid (object_enriched, object_data_changed, linkedin_job_changed, linkedin_post_published carry it): with object_sid, one cell's history. eq or a non-empty in; a sid outside pt_fd_ is a 422."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range on when the fact reached the ledger, which can be long after it happened (a history walk). New since I looked = created_at gt seen_at with an occurred_at floor (seen_at minus 3 days); when it happened = occurred_at. On metrics too.
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: Required. Half-open [from, to) window on occurred_at - the single source of truth for the time window.
        group_by:
          type: string
          enum:
            - category
            - type
            - object_type
          description: "Single axis: category | type | object_type - adds groups[] with per-value counts + metrics."
      required:
        - period
    GetActivitiesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request ActivitySearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Rows matching the filter (full filter scope, not the page).
                    groups:
                      type: object
                      properties:
                        category:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {value: count} per ActivityCategoryEnum value present in scope."
                        type:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {value: count} per ActivityTypeEnum value present in scope - the engagement-widget axis."
                        object_type:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {person: n, company: m} row counts."
                      required:
                        - category
                        - type
                        - object_type
                      description: One axis per ActivityGroupableFieldsEnum value (§4.17); PHP empty map serialises as [].
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    first_occurred_at:
                      type: string
                      nullable: true
                      description: ISO 8601 UTC - MIN(occurred_at) within period+filter scope; null when no facts in scope.
                    last_occurred_at:
                      type: string
                      nullable: true
                      description: ISO 8601 UTC - MAX(occurred_at) within period+filter scope; recency signal.
                    active_days_count:
                      type: integer
                      minimum: 0
                      description: COUNT(DISTINCT DATE(occurred_at)) - distinct UTC days with >=1 fact; engagement spread.
                  required:
                    - first_occurred_at
                    - last_occurred_at
                    - active_days_count
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: Value of the group_by axis (a category / type / object_type enum member).
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Rows matching the filter (full filter scope, not the page).
                      groups:
                        type: object
                        properties:
                          category:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {value: count} per ActivityCategoryEnum value present in scope."
                          type:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {value: count} per ActivityTypeEnum value present in scope - the engagement-widget axis."
                          object_type:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {person: n, company: m} row counts."
                        required:
                          - category
                          - type
                          - object_type
                        description: One axis per ActivityGroupableFieldsEnum value (§4.17); PHP empty map serialises as [].
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      first_occurred_at:
                        type: string
                        nullable: true
                        description: ISO 8601 UTC - MIN(occurred_at) within period+filter scope; null when no facts in scope.
                      last_occurred_at:
                        type: string
                        nullable: true
                        description: ISO 8601 UTC - MAX(occurred_at) within period+filter scope; recency signal.
                      active_days_count:
                        type: integer
                        minimum: 0
                        description: COUNT(DISTINCT DATE(occurred_at)) - distinct UTC days with >=1 fact; engagement spread.
                    required:
                      - first_occurred_at
                      - last_occurred_at
                      - active_days_count
                required:
                  - key
                  - counts
                  - metrics
              description: Present when group_by was set - one entry per axis value in scope.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetCompaniesMetricsRequest:
      type: object
      description: Request body of `get_companies_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
              additionalProperties: false
              description: Prefix-validated cr_co_ sid(s).
            playtable_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every company tab passes { in: [<table>] }; array-overlap. nin answers the complement, memberless rows included."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The account's funnel bucket (one of seven), expanded on the server into the team's company stage sids of those categories: ask by name, never resolve the stages yourself. eq approaching = someone was invited or written to and nobody answered."
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the account, all must hold: its own visit and the account names rolled up over the people to work (disqualified or stoplisted people do not count). Never compose the roll-ups yourself. A person's or a thread's name is a 422."
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance (ds_sc_…).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap (any of); cr_tg_ sids - resolve labels via tags. nin answers the complement, untagged rows included.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact LinkedIn company id.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact page slug; fuzzy matching goes through q.
            domain:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Lowercased apex; is_null = enrichment gap.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact match; substring goes through q.
            q:
              type: string
              maxLength: 128
              description: Free text over name, domain, website, ln_nickname (ES full-text).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: "Required. Period column: created_at - created_at operators inside filter are silently ignored."
        group_by:
          type: string
          enum:
            - status
            - playtable_sids
            - data_source_sid
            - pipeline_stage_sid
          description: Single-axis breakdown - one groups[] entry per value. Cap 500 groups (422 on overflow - narrow the filter).
      required:
        - period
    GetCompaniesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request CompanySearchFilter (PHP empty map serializes as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Company rows matching the filter scope.
                    with_linkedin_count:
                      type: integer
                      minimum: 0
                      description: Rows where ln_id IS NOT NULL OR ln_nickname IS NOT NULL - multi-column OR, no group axis covers it.
                    with_domain_count:
                      type: integer
                      minimum: 0
                      description: Rows where domain IS NOT NULL - filterable but not groupable column.
                    groups:
                      type: object
                      properties:
                        status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: Rows per CompanyStatusEnum value (3 values, bounded).
                        playtable_sids:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: Rows per member table (pt_tb_… keys); a company counts once per member table.
                        data_source_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: Rows per provenance source (ds_sc_… keys).
                        signals:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Rows per signal name the account carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many accounts of the scope read no_engagement, exhausted, dm_missing and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the Companies grid, Creator's brief)."
                      required:
                        - status
                        - playtable_sids
                        - data_source_sid
                        - signals
                  required:
                    - total_count
                    - with_linkedin_count
                    - with_domain_count
                    - groups
                metrics:
                  type: object
                  properties:
                    added_count:
                      type: integer
                      minimum: 0
                      description: Rows with created_at within [period.from, period.to).
                    deleted_count:
                      type: integer
                      minimum: 0
                      description: Rows soft-deleted within the period (counted with deleted scope).
                    linkedin_coverage_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: with_linkedin_count / total_count over the filter scope; null when total is 0.
                    domain_coverage_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: with_domain_count / total_count; null when total is 0.
                  required:
                    - added_count
                    - deleted_count
                    - linkedin_coverage_rate
                    - domain_coverage_rate
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    nullable: true
                    description: Value of the group_by axis (status value / pt_tb_ / ds_sc_ sid); null = rows without a value.
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Company rows matching the filter scope.
                      with_linkedin_count:
                        type: integer
                        minimum: 0
                        description: Rows where ln_id IS NOT NULL OR ln_nickname IS NOT NULL - multi-column OR, no group axis covers it.
                      with_domain_count:
                        type: integer
                        minimum: 0
                        description: Rows where domain IS NOT NULL - filterable but not groupable column.
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: Rows per CompanyStatusEnum value (3 values, bounded).
                          playtable_sids:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: Rows per member table (pt_tb_… keys); a company counts once per member table.
                          data_source_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: Rows per provenance source (ds_sc_… keys).
                          signals:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Rows per signal name the account carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many accounts of the scope read no_engagement, exhausted, dm_missing and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the Companies grid, Creator's brief)."
                        required:
                          - status
                          - playtable_sids
                          - data_source_sid
                          - signals
                    required:
                      - total_count
                      - with_linkedin_count
                      - with_domain_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      added_count:
                        type: integer
                        minimum: 0
                        description: Rows with created_at within [period.from, period.to).
                      deleted_count:
                        type: integer
                        minimum: 0
                        description: Rows soft-deleted within the period (counted with deleted scope).
                      linkedin_coverage_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: with_linkedin_count / total_count over the filter scope; null when total is 0.
                      domain_coverage_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: with_domain_count / total_count; null when total is 0.
                    required:
                      - added_count
                      - deleted_count
                      - linkedin_coverage_rate
                      - domain_coverage_rate
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetCompanyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        included:
          type: object
          properties:
            people_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
              description: PeopleCounts aggregate over the company's linked people (legacy leads-summary widget); FK auto-injected (people.company_sid = parent.sid), no other filters pass - see ./people.md.
            field_values:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: "Trimmed cell projection (value, status, cost, finished_at - no meta.steps) across ALL member playtables; each row carries its playtable_sid. Order: playtable_sid, then field position. Full trace = playtable-field-values get - see ./playtable_field_values.md."
            last_activities:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: ActivityDomain rows (1:N, limit 20, occurred_at DESC) - see ./activities.md.
            notes:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: NoteDomain rows (1:N, limit 20, created_at DESC) - see ./notes.md.
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  since:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: the instant the signal's clock started (our last message, the accept, the reaction...). null when the signal has no clock (draft_pending)."
                  age_days:
                    type: integer
                    nullable: true
                    minimum: 0
                    description: Whole days since `since`, at read time. null when the signal has no clock.
                required:
                  - key
                  - since
                  - age_days
              description: "The catalog names the account carries right now, evaluated at read time from the ledger: its own website visit (company_visited_our_site) and the account names over its people (ACCOUNT_PLAYS_RESEARCH.md §4.2: no_people, thin_coverage, nobody_reached, no_engagement, no_reply, exhausted, dormant, dm_missing), each with the instant its clock started and its age in days (both null for a stored fact with no clock). Empty when none holds. Read it before deciding where to top up or whom to re-engage."
            freshness:
              type: array
              items:
                type: object
                properties:
                  object_sid:
                    type: string
                    description: "The row: cr_pp_ on a person, cr_co_ on a company."
                  kind:
                    type: string
                    enum:
                      - profile
                      - company
                      - posts
                    description: "profile: the LinkedIn profile (a people-tab column over the person). company: the company page (a people-tab column over a company URL on a person; a companies-tab column on a company). posts: the person's posts."
                  read_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: the row's last read of this kind, whoever read (the play, a workflow's Run column step, a column's own run, a hand run). null = never read."
                  play_sid:
                    type: string
                    description: "pt_pl_ the play whose schedule keeps this kind fresh on the row: switched on, daily, its watch names the kind, a column of the row's tab reads the kind, and the row is in its audience (a company is when one of its people is). When several plays cover the row and the kind, the shortest cadence wins."
                  play_name:
                    type: string
                    description: The play's name, for "re-read 2 days ago by Keep data fresh".
                  days:
                    type: integer
                    minimum: 0
                    exclusiveMinimum: true
                    description: The play's cadence for this kind, in days ("every 7 days").
                  next_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: read_at plus the cadence, when the schedule reads the row again. null when never read: the next run reads it."
                required:
                  - object_sid
                  - kind
                  - read_at
                  - play_sid
                  - play_name
                  - days
                  - next_at
              description: "The company page's read when a watching play keeps it fresh on the company (a companies-tab column reads it, one of the company's people is in the play's audience): the play, its cadence, the last read and the next. Empty when no switched-on daily play covers the company."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetCreditLedgerEntriesMetricsRequest:
      type: object
      description: Request body of `get_credit_ledger_entries_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cl_en_
                  description: Credit ledger entry (receipt) sid (cl_en_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cl_en_
                    description: Credit ledger entry (receipt) sid (cl_en_…).
              additionalProperties: false
              description: Receipt sid(s), cl_en_ prefix (prefix-validated).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: Per-table spend scope (pt_tb_…).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
              additionalProperties: false
              description: "Residual inside scope: people | company."
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: cr_pp_… / cr_co_… (mixed prefixes - not prefix-pinned); cell drill-down with playtable_field_sid.
            playtable_field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: Per-field spend scope (pt_fd_…).
            run_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_rn_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rn_
                is_null:
                  type: boolean
              additionalProperties: false
              description: What a run cost (pt_rn_…); is_null:true = non-run spend (empty in v1 - the cell-waterfall writer always carries a run).
            tool_sid:
              type: object
              properties:
                eq:
                  type: string
                  maxLength: 64
                in:
                  type: array
                  items:
                    type: string
                    maxLength: 64
              additionalProperties: false
              description: Spend through one gtm-api tool (external sid, opaque).
            created_by_actor_sid:
              type: object
              properties:
                eq:
                  type: string
              additionalProperties: false
              description: '"What did this person spend" - projected from created_by.actor_sid.'
            idempotency_key:
              type: object
              properties:
                eq:
                  type: string
                  maxLength: 128
              additionalProperties: false
              description: "Support/debug: locate one exact charge."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range - day windows; combine bounds in one object. Ignored on metrics - period owns the window.
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: Required. Half-open [from, to) window on created_at (the receipt clock) - created_at operators inside filter are silently ignored.
        group_by:
          type: string
          enum:
            - playtable_sid
            - playtable_field_sid
            - tool_sid
            - created_date
          description: "Single spend axis: playtable_sid | playtable_field_sid | tool_sid | created_date - adds groups[] with per-value counts + metrics. Cap 500 groups (§4.17)."
      required:
        - period
    GetCreditLedgerEntriesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request CreditLedgerEntrySearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Receipts (paid calls) matching the filter - full filter scope, not the page.
                    groups:
                      type: object
                      properties:
                        playtable_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {pt_tb_ sid: call count} - which table is spending."
                        playtable_field_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {pt_fd_ sid: call count} - call concentration by field."
                        tool_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {tool_sid: call count} - calls through each gtm-api tool."
                        created_date:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                            - type: array
                              items: {}
                          description: "Flat {'YYYY-MM-DD': call count} - calls per UTC day (≤ 366 values under 12-month retention)."
                      required:
                        - playtable_sid
                        - playtable_field_sid
                        - tool_sid
                        - created_date
                      description: One axis per CreditLedgerEntryGroupableFieldsEnum value (§4.17). Values are CALL COUNTS - credit sums live in the metrics tool. PHP empty map serialises as [].
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    spent:
                      type: number
                      minimum: 0
                      description: Σ cost (credits, decimal(12,4)) over receipts in [from, to) at filter scope.
                    paid_calls_count:
                      type: integer
                      minimum: 0
                      description: Receipts (paid calls) in [from, to) - period-bound, unlike counts.total_count (filter scope).
                  required:
                    - spent
                    - paid_calls_count
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    nullable: true
                    description: "Value of the group_by axis: a pt_tb_ / pt_fd_ sid, a gtm-api tool_sid, or a 'YYYY-MM-DD' date; null = rows without a value on the axis."
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Receipts (paid calls) matching the filter - full filter scope, not the page.
                      groups:
                        type: object
                        properties:
                          playtable_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {pt_tb_ sid: call count} - which table is spending."
                          playtable_field_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {pt_fd_ sid: call count} - call concentration by field."
                          tool_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {tool_sid: call count} - calls through each gtm-api tool."
                          created_date:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: "Flat {'YYYY-MM-DD': call count} - calls per UTC day (≤ 366 values under 12-month retention)."
                        required:
                          - playtable_sid
                          - playtable_field_sid
                          - tool_sid
                          - created_date
                        description: One axis per CreditLedgerEntryGroupableFieldsEnum value (§4.17). Values are CALL COUNTS - credit sums live in the metrics tool. PHP empty map serialises as [].
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      spent:
                        type: number
                        minimum: 0
                        description: Σ cost (credits, decimal(12,4)) over receipts in [from, to) at filter scope.
                      paid_calls_count:
                        type: integer
                        minimum: 0
                        description: Receipts (paid calls) in [from, to) - period-bound, unlike counts.total_count (filter scope).
                    required:
                      - spent
                      - paid_calls_count
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value in scope.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        included:
          type: object
          properties:
            playtable:
              type: object
              properties:
                sid:
                  type: string
              required:
                - sid
              description: PlaytableDomain (1:1 via playtable_sid) - see ./playtables.md.
            sender_profile:
              type: object
              properties:
                sid:
                  type: string
              required:
                - sid
              description: SenderProfileDomain (1:1 via sender_profile_sid), the sender profile that collects a sender search or a post engagement; its linkedin_has_sn / linkedin_recruiter_status say which links it can open - see ./sender_profiles.md.
            data_source_items_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                groups:
                  type: object
                  properties:
                    status:
                      anyOf:
                        - type: object
                          additionalProperties:
                            type: number
                        - type: array
                          items: {}
                      description: "The import funnel: pending / promoted / duplicate / stoplisted / failed."
                  required:
                    - status
              required:
                - total_count
                - groups
              description: "DataSourceItemCounts computed over { data_source_sid: parent.sid } - the per-source import funnel at full scope (§4.17 parent-include) - see ./data_source_items.md."
            indexed_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
              description: How many of the source's objects are already VISIBLE in the People / Companies grids (the read-plane twin of the funnel's `promoted`, which counts MySQL truth the moment an item lands). Quote this one, not `promoted`, next to a link into the grid.
            csv_preview:
              type: object
              nullable: true
              properties:
                headers:
                  type: array
                  items:
                    type: string
                rows:
                  type: array
                  items:
                    type: array
                    items:
                      type: string
                      nullable: true
                total_rows:
                  type: integer
                  minimum: 0
              required:
                - headers
                - rows
                - total_rows
              description: "type=csv only: header row + the first 5 data rows + total_rows, replayed from the stored file so a draft's mapping step can resume. null for every other kind and for an unreadable file. Request it on get, not as list hydration."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        ingest_url:
          type: string
          description: "type=webhook only: the source's current ingest URL, {api_base}/external/ingest/{ingest_key}, the same value create answered; absent for every other kind. Hand it over a channel the user trusts; rotate_data_source_ingest_key revokes it."
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetDataSourcesMetricsRequest:
      type: object
      description: Request body of `get_data_sources_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                  description: Data source sid (ds_sc_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                    description: Data source sid (ds_sc_…).
              additionalProperties: false
              description: Prefix-validated ds_sc_ sid(s).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Sources feeding table X; is_null:true = orphaned by playtable deletion.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ai_search
                    - sender_search
                    - post_engagement
                    - find_people
                    - csv
                    - webhook
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ai_search
                      - sender_search
                      - post_engagement
                      - find_people
                      - csv
                      - webhook
              additionalProperties: false
              description: "The kind tabs of the sources page: ai_search | sender_search | post_engagement | find_people | csv | webhook."
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - people
                      - company
              additionalProperties: false
              description: "What the source brings: people | company."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Sources run by a given sender profile (ub_sp_…); is_null:true = everything the platform pool or a file feeds.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - completed
                    - failed
                ne:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - completed
                    - failed
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - completed
                      - failed
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - completed
                      - failed
              additionalProperties: false
            q:
              type: string
              maxLength: 128
              description: Free text over name only (MySQL LIKE, infix).
            next_collect_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Due/overdue scans; ISO 8601. is_null:true = clock-less (csv, webhook, and a bus-served sender search).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: "Required. {from, to} ISO 8601 UTC, half-open: compute the window from the date the client knows (the last 7 days = today minus 7 to now), never from a read. Bounds the funnel by data_source_items.created_at; filter (incl. created_at) scopes source rows."
        group_by:
          type: string
          enum:
            - status
            - type
            - object_type
          description: Single axis - adds groups[] with per-value counts + metrics. Cap 500 groups.
      required:
        - period
    GetDataSourcesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request DataSourceSearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Source rows matching the filter scope.
                    groups:
                      type: object
                      properties:
                        status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        type:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        object_type:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                      required:
                        - status
                        - type
                        - object_type
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    items_collected:
                      type: integer
                      minimum: 0
                      description: Items created within [period.from, period.to), sources in filter scope.
                    items_promoted:
                      type: integer
                      minimum: 0
                      description: Items whose terminal transition to promoted fell in the period.
                    items_duplicate:
                      type: integer
                      minimum: 0
                      description: Items resolved duplicate in the period (identity ladder matched a live object).
                    items_stoplisted:
                      type: integer
                      minimum: 0
                      description: Items blocked by a stoplist match in the period.
                    items_disqualified:
                      type: integer
                      minimum: 0
                      description: Items the source gate turned away in the period (2026-10-13).
                    items_failed:
                      type: integer
                      minimum: 0
                      description: Items whose promotion errored in the period.
                    promotion_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: items_promoted / items_collected; null when items_collected is 0.
                    last_collected_at:
                      type: string
                      nullable: true
                      description: MAX(items.created_at) in scope - freshest ingestion; ISO 8601 UTC, null if none.
                  required:
                    - items_collected
                    - items_promoted
                    - items_duplicate
                    - items_stoplisted
                    - items_disqualified
                    - items_failed
                    - promotion_rate
                    - last_collected_at
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: Value of the group_by axis (a status / type / object_type value).
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Source rows matching the filter scope.
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          type:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          object_type:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                        required:
                          - status
                          - type
                          - object_type
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      items_collected:
                        type: integer
                        minimum: 0
                        description: Items created within [period.from, period.to), sources in filter scope.
                      items_promoted:
                        type: integer
                        minimum: 0
                        description: Items whose terminal transition to promoted fell in the period.
                      items_duplicate:
                        type: integer
                        minimum: 0
                        description: Items resolved duplicate in the period (identity ladder matched a live object).
                      items_stoplisted:
                        type: integer
                        minimum: 0
                        description: Items blocked by a stoplist match in the period.
                      items_disqualified:
                        type: integer
                        minimum: 0
                        description: Items the source gate turned away in the period (2026-10-13).
                      items_failed:
                        type: integer
                        minimum: 0
                        description: Items whose promotion errored in the period.
                      promotion_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: items_promoted / items_collected; null when items_collected is 0.
                      last_collected_at:
                        type: string
                        nullable: true
                        description: MAX(items.created_at) in scope - freshest ingestion; ISO 8601 UTC, null if none.
                    required:
                      - items_collected
                      - items_promoted
                      - items_duplicate
                      - items_stoplisted
                      - items_disqualified
                      - items_failed
                      - promotion_rate
                      - last_collected_at
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value. Cap 500 groups → 422.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetPeopleMetricsRequest:
      type: object
      description: Request body of `get_people_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
              additionalProperties: false
              description: Prefix-validated cr_pp_ sid(s).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every table view passes { eq: <table> }."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The stage's funnel bucket (one of seven), expanded on the server into the team's person stage sids of those categories: ask by name, never resolve stages. eq approaching = we reached out, nothing came back; in [engaging, positive] = something came back."
            company_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                is_null:
                  type: boolean
              additionalProperties: false
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            linkedin_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                ne:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
              additionalProperties: false
            email_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                is_null:
                  type: boolean
              additionalProperties: false
            phone_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                is_null:
                  type: boolean
              additionalProperties: false
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap semantics (any of) - in matches rows whose tag array overlaps the list; nin answers the complement, untagged rows included.
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the person, all must hold. The server expands a name into its keyword and clock range: never compose them. A bare entry takes the catalog default age, age_days moves it. A thread-only name is a 422 (ask search_conversations)."
            ln_member_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact identifier.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw profile URN.
            sn_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw Sales Navigator URN.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact vanity slug (lowercased); use q for fuzzy.
            work_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: is_null:true = coverage gap.
            personal_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
            q:
              type: string
              maxLength: 128
              description: Free text (ES people index) over the resolved name and company name, the emails and the slug. Filter a company by company_sid.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: Required. Single source of truth for the time window; period column = created_at.
        group_by:
          type: string
          enum:
            - status
            - linkedin_status
            - email_status
            - phone_status
            - playtable_sid
            - data_source_sid
            - pipeline_stage_sid
          description: Single axis from the groupable fields - adds groups[] with per-value counts + metrics. Cap 500 groups.
      required:
        - period
    GetPeopleMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request PeopleSearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: People rows matching the filter scope.
                    with_email_count:
                      type: integer
                      minimum: 0
                      description: work_email IS NOT NULL OR personal_email IS NOT NULL (multi-column OR).
                    with_phone_count:
                      type: integer
                      minimum: 0
                      description: work_phone_number IS NOT NULL OR personal_phone_number IS NOT NULL (multi-column OR).
                    with_linkedin_count:
                      type: integer
                      minimum: 0
                      description: "Any LinkedIn identity axis present: ln_member_id, ln_id, sn_id, recruiter_id or ln_nickname (multi-column OR)."
                    with_company_count:
                      type: integer
                      minimum: 0
                      description: company_sid IS NOT NULL (filterable but not groupable column).
                    groups:
                      type: object
                      properties:
                        status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        linkedin_status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        email_status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        phone_status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        playtable_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        data_source_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                        signals:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: "Rows per signal name the person carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many people of the scope read awaiting_reply, went_quiet, dormant and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the People grid)."
                      required:
                        - status
                        - linkedin_status
                        - email_status
                        - phone_status
                        - playtable_sid
                        - data_source_sid
                        - signals
                  required:
                    - total_count
                    - with_email_count
                    - with_phone_count
                    - with_linkedin_count
                    - with_company_count
                    - groups
                metrics:
                  type: object
                  properties:
                    added_count:
                      type: integer
                      minimum: 0
                      description: Rows with created_at within [period.from, period.to).
                    deleted_count:
                      type: integer
                      minimum: 0
                      description: Rows soft-deleted within the period (counted with deleted scope).
                    email_coverage_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: with_email_count / total_count over the filter scope; null when total is 0.
                    linkedin_coverage_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: with_linkedin_count / total_count; null when total is 0.
                    phone_coverage_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: with_phone_count / total_count; null when total is 0.
                  required:
                    - added_count
                    - deleted_count
                    - email_coverage_rate
                    - linkedin_coverage_rate
                    - phone_coverage_rate
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    nullable: true
                    description: Value of the group_by axis (enum value / sid); null = rows without a value on the axis.
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: People rows matching the filter scope.
                      with_email_count:
                        type: integer
                        minimum: 0
                        description: work_email IS NOT NULL OR personal_email IS NOT NULL (multi-column OR).
                      with_phone_count:
                        type: integer
                        minimum: 0
                        description: work_phone_number IS NOT NULL OR personal_phone_number IS NOT NULL (multi-column OR).
                      with_linkedin_count:
                        type: integer
                        minimum: 0
                        description: "Any LinkedIn identity axis present: ln_member_id, ln_id, sn_id, recruiter_id or ln_nickname (multi-column OR)."
                      with_company_count:
                        type: integer
                        minimum: 0
                        description: company_sid IS NOT NULL (filterable but not groupable column).
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          linkedin_status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          email_status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          phone_status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          playtable_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          data_source_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                          signals:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: "Rows per signal name the person carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many people of the scope read awaiting_reply, went_quiet, dormant and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the People grid)."
                        required:
                          - status
                          - linkedin_status
                          - email_status
                          - phone_status
                          - playtable_sid
                          - data_source_sid
                          - signals
                    required:
                      - total_count
                      - with_email_count
                      - with_phone_count
                      - with_linkedin_count
                      - with_company_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      added_count:
                        type: integer
                        minimum: 0
                        description: Rows with created_at within [period.from, period.to).
                      deleted_count:
                        type: integer
                        minimum: 0
                        description: Rows soft-deleted within the period (counted with deleted scope).
                      email_coverage_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: with_email_count / total_count over the filter scope; null when total is 0.
                      linkedin_coverage_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: with_linkedin_count / total_count; null when total is 0.
                      phone_coverage_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: with_phone_count / total_count; null when total is 0.
                    required:
                      - added_count
                      - deleted_count
                      - email_coverage_rate
                      - linkedin_coverage_rate
                      - phone_coverage_rate
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value. Cap 500 groups.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetPersonResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              description: pt_tb_… - the SINGLE playtable membership; service-managed, changes only via move (create on_duplicate:move / run type move).
            data_source_sid:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            company_sid:
              type: string
              nullable: true
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                first_name:
                  type: string
                  nullable: true
                  description: The source's own first name when it gave one, else the first word of name.
                picture_url:
                  type: string
                  nullable: true
                  description: A permanent copy over a wire link, the wire link that lasts longest, an expired one counts as none.
                role:
                  type: string
                  nullable: true
                  description: The title at the company (the Sales Navigator wire's position, the enrichment's).
                headline:
                  type: string
                  nullable: true
                  description: The profile line (the regular and Recruiter wires, the inbox participant, the enrichment).
                company:
                  type: object
                  nullable: true
                  properties:
                    sid:
                      type: string
                      nullable: true
                      description: cr_co_… when the person is linked to an account (the account's own resolved context follows); null = a name that is not an account, an import whose company column resolved to none.
                    name:
                      type: string
                      nullable: true
                    domain:
                      type: string
                      nullable: true
                    picture_url:
                      type: string
                      nullable: true
                    ln_id:
                      type: string
                      nullable: true
                      description: "The company's LinkedIn id: the linked account's own, else the person's company id as a source or an edit gave it."
                  required:
                    - sid
                    - name
                    - domain
                    - picture_url
                    - ln_id
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - first_name
                - picture_url
                - role
                - headline
                - company
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, first name, picture, role, headline and company a surface or a model shows next to the row, resolved at read from the observations ledger: a manual word until reset, then the newest LinkedIn-derived observation, then any other. The only place these words are: the row keeps identifiers (phase E, 2026-10-22). Null only on an event payload."
            ln_member_id:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
            sn_id:
              type: string
              nullable: true
            recruiter_id:
              type: string
              nullable: true
            work_email:
              type: string
              nullable: true
            personal_email:
              type: string
              nullable: true
            work_phone_number:
              type: string
              nullable: true
            personal_phone_number:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - no_contact_data
                - duplicate
                - stoplisted
              description: Service-managed row validity (import validation, stoplist, duplicate detection) - not client-writable.
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY row (cr_pp_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_person_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_member_id
                - ln_id
                - sn_id
                - recruiter_id
                - email
                - ln_nickname
                - phone
              description: "While status is duplicate: the identifier the check matched on. Null otherwise."
            linkedin_status:
              type: string
              enum:
                - need_enrichment
                - enrichment_failed
                - no_data
                - blocked
                - ok
            email_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - bounced
                - ok
                - catch_all
                - unverified
            phone_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - ok
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: Free-form CRM sync map (hubspot_contact_id, …) - keys integration-defined, round-tripped as-is; PHP empty map serialises as [].
            last_enrich_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: The funnel stage the person is in (cr_ps_...), derived from activity or moved by hand (pipeline_stages.md); null = no stage.
          required:
            - sid
            - team_sid
            - playtable_sid
            - data_source_sid
            - data_source_item_sid
            - company_sid
            - context
            - ln_member_id
            - ln_id
            - sn_id
            - recruiter_id
            - work_email
            - personal_email
            - work_phone_number
            - personal_phone_number
            - status
            - duplicate_of_sid
            - duplicate_matched_kind
            - linkedin_status
            - email_status
            - phone_status
            - tag_sids
            - external_refs
            - last_enrich_at
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
        included:
          type: object
          properties:
            company:
              type: object
              nullable: true
              properties:
                sid:
                  type: string
              required:
                - sid
              description: CompanyDomain (N:1 via company_sid) - see ./companies.md.
            field_values:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: "PlaytableFieldValueDomain rows - ALL live cells of the person's playtable (the table-row hydration: renders the custom columns), ordered by field position - see ./playtable_field_values.md."
            workflow_records:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: WorkflowRecordDomain rows in a NON-TERMINAL status only (active memberships; 1:N, limit 20, created_at DESC) - see ./workflow_records.md.
            last_activities:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: ActivityDomain rows (1:N, limit 20, occurred_at DESC) - the ingested timeline - see ./activities.md.
            notes:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: NoteDomain rows (1:N, limit 20, created_at DESC) - see ./notes.md.
            engagement:
              type: object
              properties: {}
              description: "The person's engagement counters and dates folded over EVERY fact of the activities ledger (the search document's `engagement` keys, D43: messages sent and received per channel, opens, clicks, invitations sent / accepted / withdrawn, visits, likes, comments, endorsements, bounces, unsubscribes, replies, touches, the last touch and last message with their channel and direction). Every key present: 0 / null until a fact moves it. What the LinkedIn channel and Email channel widget cells draw; shares one read with engagement_by_sender."
            engagement_by_sender:
              type: array
              items:
                type: object
                properties:
                  sender_profile_sid:
                    type: string
                required:
                  - sender_profile_sid
              description: "The same counters per sender profile (ub_sp_ sid): the facts whose payload names it. Empty when no fact of the person names a sender profile."
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  since:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: the instant the signal's clock started (our last message, the accept, the reaction...). null when the signal has no clock (draft_pending)."
                  age_days:
                    type: integer
                    nullable: true
                    minimum: 0
                    description: Whole days since `since`, at read time. null when the signal has no clock.
                required:
                  - key
                  - since
                  - age_days
              description: "The catalog names the person carries right now (SIGNALS_RESEARCH.md §5.3: evaluated from the engagement counters across every sender profile), each with the instant its clock started and its age in days. Empty when none holds. Ask it before drafting or deciding a next step; the thread-level names (drafts, escalations, tasks, reactions) are get_conversation's."
            freshness:
              type: array
              items:
                type: object
                properties:
                  object_sid:
                    type: string
                    description: "The row: cr_pp_ on a person, cr_co_ on a company."
                  kind:
                    type: string
                    enum:
                      - profile
                      - company
                      - posts
                    description: "profile: the LinkedIn profile (a people-tab column over the person). company: the company page (a people-tab column over a company URL on a person; a companies-tab column on a company). posts: the person's posts."
                  read_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: the row's last read of this kind, whoever read (the play, a workflow's Run column step, a column's own run, a hand run). null = never read."
                  play_sid:
                    type: string
                    description: "pt_pl_ the play whose schedule keeps this kind fresh on the row: switched on, daily, its watch names the kind, a column of the row's tab reads the kind, and the row is in its audience (a company is when one of its people is). When several plays cover the row and the kind, the shortest cadence wins."
                  play_name:
                    type: string
                    description: The play's name, for "re-read 2 days ago by Keep data fresh".
                  days:
                    type: integer
                    minimum: 0
                    exclusiveMinimum: true
                    description: The play's cadence for this kind, in days ("every 7 days").
                  next_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: read_at plus the cadence, when the schedule reads the row again. null when never read: the next run reads it."
                required:
                  - object_sid
                  - kind
                  - read_at
                  - play_sid
                  - play_name
                  - days
                  - next_at
              description: "Per read kind a watching play keeps fresh on the person (the LinkedIn profile, the company page a people-tab column reads, the posts): the play, its cadence, the last read and the next. One entry per kind at most; empty when no switched-on daily play covers the person. How old a profile read is, and whether the table re-reads it on its own."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPipelineStagesMetricsRequest:
      type: object
      description: Request body of `get_pipeline_stages_metrics`.
      properties:
        object:
          type: string
          enum:
            - person
            - company
          description: "Which funnel to count: person (over the people index) or company (over the companies index, which is also what enables deal_sum)."
        filter:
          type: object
          additionalProperties: {}
          description: "Optional scope: a people filter when object is person, a company filter when it is company (operator objects as on the search tools, e.g. {playtable_sid: {eq: pt_tb_...}}). Omitted = the whole team. deleted_at is ignored: the funnel counts live rows only."
      required:
        - object
    GetPipelineStagesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          additionalProperties:
            type: object
            properties:
              count:
                type: integer
                minimum: 0
                description: Objects currently in this stage, within the request filter.
              deal_sum:
                type: number
                nullable: true
                description: Sum of companies.deal_size over the stage; present for object:'company' only, null for a person funnel.
            required:
              - count
          description: Keyed by stage sid (cr_ps_…), plus a "null" key carrying the objects with no stage. A stage with no objects is absent from the map, not a zero row.
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        categories:
          type: object
          properties:
            cold:
              type: integer
              minimum: 0
            approaching:
              type: integer
              minimum: 0
            engaging:
              type: integer
              minimum: 0
            positive:
              type: integer
              minimum: 0
            nurture:
              type: integer
              minimum: 0
            negative:
              type: integer
              minimum: 0
            disqualified:
              type: integer
              minimum: 0
          description: 'The same counts folded per category, every one of the seven present (0 when empty); the "null" bucket folds into none. Read this for "how many are approaching": never fold the stage map yourself.'
      required:
        - success
        - operation
        - metrics
        - meta
        - categories
    GetPlaytableFieldResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object grid this field belongs to: people or company rows. Fixed at create."
            name:
              type: string
              description: Display label, freely editable.
            slug:
              type: string
              description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
            category:
              type: string
              enum:
                - scalar
                - widget
                - action
              description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
            type:
              type: string
              enum:
                - scalar_text
                - scalar_number
                - scalar_currency
                - scalar_date
                - scalar_url
                - scalar_checkbox
                - scalar_select
                - scalar_multiselect
                - scalar_image
                - widget_data_source
                - widget_tags
                - widget_active_workflows
                - widget_notes
                - widget_company
                - widget_linkedin_id
                - widget_linkedin_channel
                - widget_work_email
                - widget_personal_email
                - widget_email_channel
                - widget_phones
                - widget_phone_channel
                - widget_last_touch
                - widget_activity
                - widget_deal_size
                - widget_website
                - widget_people_summary
                - widget_ai_sdr
                - action_ai_research
                - action_waterfall
                - action_gtm_tool
                - action_find_people
              description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
            payload:
              anyOf:
                - type: object
                  properties:
                    formula:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                    template:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                    nl_formula:
                      type: string
                      nullable: true
                      maxLength: 2048
                      description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                    currency:
                      type: string
                      nullable: true
                      pattern: ^[A-Z]{3}$
                      description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                    option_colors:
                      type: object
                      nullable: true
                      additionalProperties:
                        type: string
                        pattern: ^#[0-9a-f]{6}$
                      description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                  required:
                    - formula
                    - template
                    - nl_formula
                    - options
                    - currency
                    - option_colors
                - type: object
                  properties: {}
                  additionalProperties: false
                  description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^wf_wf_
                      description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                  required:
                    - workflow_sid
                  additionalProperties: false
                - type: object
                  properties:
                    stats_view:
                      type: string
                      enum:
                        - all
                        - last
                        - select
                      description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                    sender_profile_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^ub_sp_
                      description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                  required:
                    - stats_view
                    - sender_profile_sid
                  additionalProperties: false
                - type: object
                  properties:
                    prompt:
                      type: string
                      minLength: 1
                      maxLength: 8192
                      description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                    model:
                      type: string
                      minLength: 1
                      maxLength: 128
                      description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                    output:
                      type: string
                      enum:
                        - text
                        - number
                        - select
                        - json
                      description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Required (min 1) when output=select; null otherwise.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                    web_search:
                      type: boolean
                      description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                  required:
                    - prompt
                    - model
                    - output
                    - options
                    - output_mapping
                - type: object
                  properties:
                    steps:
                      type: array
                      items:
                        type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                        required:
                          - tool_sid
                          - params
                      maxItems: 10
                      description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                    stop_on_first:
                      type: boolean
                      description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                    verify:
                      type: object
                      nullable: true
                      properties:
                        tool_sid:
                          type: string
                          minLength: 1
                          description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                        params:
                          type: object
                          additionalProperties: {}
                          description: Tool params; string values may be Twig templates over the same variable namespace.
                      required:
                        - tool_sid
                        - params
                      description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                    accept_catch_all:
                      type: boolean
                      description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                  required:
                    - steps
                    - stop_on_first
                    - output_mapping
                - type: object
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: gtm-api tool registry sid (external format); existence + price validated at save.
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                  required:
                    - tool_sid
                    - params
                    - output_mapping
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                    per_company_limit:
                      type: integer
                      minimum: 1
                      maximum: 25
                      description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                    qualify:
                      type: object
                      nullable: true
                      properties:
                        "on":
                          type: boolean
                          description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                        criterion:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 2000
                          description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                      required:
                        - "on"
                        - criterion
                      additionalProperties: false
                      description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
              description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                run_condition:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                nl_condition:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                daily_credit_limit:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
              required:
                - auto_run
                - run_condition
                - nl_condition
                - daily_credit_limit
                - preset_sid
            backfill:
              type: object
              nullable: true
              properties:
                status:
                  type: string
                  enum:
                    - queued
                    - running
                    - done
                    - failed
                scanned:
                  type: integer
                  minimum: 0
                  description: Objects the scan has visited so far.
                total:
                  type: integer
                  nullable: true
                  minimum: 0
                  description: The scan size, known once the job starts (null while queued).
                queued_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the column started owing its backfill."
                started_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the job took it."
                finished_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when it ended, done or failed."
                error:
                  type: string
                  nullable: true
                  description: A reason token (backfill_failed) on failed, never an exception message.
              required:
                - status
                - scanned
                - total
                - queued_at
                - started_at
                - finished_at
                - error
              description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - slug
            - category
            - type
            - payload
            - config
            - backfill
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        included:
          type: object
          properties:
            playtable:
              type: object
              additionalProperties: {}
              description: Owner playtable row (PlaytableDomain - owned by the playtables entity).
            deps:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                  field_sid:
                    type: string
                    description: The consumer/derived field (pt_fd_…).
                  depends_on_field_sid:
                    type: string
                    description: The source field being read (pt_fd_…).
                  kind:
                    type: string
                    enum:
                      - formula
                      - prompt
                      - condition
                      - params
                    description: Construct that produced the edge (formula covers deep-ref extraction columns - edge lands on the root slug).
                  created_at:
                    type: string
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - field_sid
                  - depends_on_field_sid
                  - kind
                  - created_at
              description: Edges this field READS (field_sid = this). Default limit 100, created_at ASC.
            dependents:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                  field_sid:
                    type: string
                    description: The consumer/derived field (pt_fd_…).
                  depends_on_field_sid:
                    type: string
                    description: The source field being read (pt_fd_…).
                  kind:
                    type: string
                    enum:
                      - formula
                      - prompt
                      - condition
                      - params
                    description: Construct that produced the edge (formula covers deep-ref extraction columns - edge lands on the root slug).
                  created_at:
                    type: string
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - field_sid
                  - depends_on_field_sid
                  - kind
                  - created_at
              description: Edges that READ this field (depends_on_field_sid = this) - the pre-delete safety check. Default limit 100, created_at ASC.
            playtable_field_values_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                groups:
                  type: object
                  properties:
                    status:
                      anyOf:
                        - type: object
                          additionalProperties:
                            type: integer
                        - type: array
                          items: {}
                      description: Cells per status (empty | queued | running | done | error | run_condition_not_met).
                    playtable_field_sid:
                      anyOf:
                        - type: object
                          additionalProperties:
                            type: integer
                        - type: array
                          items: {}
                  required:
                    - status
                    - playtable_field_sid
              required:
                - total_count
                - groups
              description: Per-field cell execution progress.
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPlaytableFieldValueResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            object_sid:
              type: string
            playtable_field_sid:
              type: string
            value:
              type: string
              nullable: true
            is_value_from_formula:
              type: boolean
            original_value:
              type: string
              nullable: true
              description: "The system-produced value the FIRST manual overwrite snapshotted, what reset restores; null unless is_overwritten. The list surface nulls it like meta: read it on get, update, write and reset."
            is_overwritten:
              type: boolean
              description: "The current value is a manual write over a system-produced one: the edited marker, and the one state reset accepts."
            is_not_valid:
              type: boolean
              description: A manually written value that could not be converted to the column's type (text in a number column), stored raw and flagged; system writers coerce or null instead.
            status:
              type: string
              enum:
                - empty
                - queued
                - running
                - done
                - error
                - run_condition_not_met
            cost:
              type: number
              nullable: true
            provider_sid:
              type: string
              nullable: true
            meta:
              type: object
              nullable: true
              properties:
                run_sid:
                  type: string
                  nullable: true
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      step_index:
                        type: number
                      tool_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - success
                          - failed
                          - skipped
                      cost:
                        type: number
                      error:
                        type: string
                        nullable: true
                      finished_at:
                        type: string
                        nullable: true
                      verdict:
                        type: string
                        nullable: true
                      email:
                        type: string
                        nullable: true
                    required:
                      - step_index
                      - tool_sid
                      - status
                      - cost
                      - error
                      - finished_at
              required:
                - run_sid
                - steps
            error_msg:
              type: string
              nullable: true
            finished_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - object_sid
            - playtable_field_sid
            - value
            - is_value_from_formula
            - original_value
            - is_overwritten
            - is_not_valid
            - status
            - cost
            - provider_sid
            - meta
            - error_msg
            - finished_at
            - created_at
            - updated_at
        included:
          type: object
          properties:
            field:
              type: object
              properties:
                sid:
                  type: string
                name:
                  type: string
                slug:
                  type: string
                category:
                  type: string
                type:
                  type: string
              required:
                - sid
                - name
                - slug
                - category
                - type
              description: "1:1 owning field (include[]=field): name, slug, category, type; config carries run_condition / nl_condition / preset."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPlaytablePerformanceRequest:
      type: object
      description: Request body of `get_playtable_performance`.
      properties:
        days:
          type: integer
          minimum: 1
          maximum: 90
          description: "The window in the workspace's days, today included (the Overview shows 30 by default; its 24 hours is 1, today). Either this or from + to, never both. The series covers twice as many days: this window and the one before it, to compare against."
        from:
          type: string
          description: "A custom range instead of `days`: its first day, YYYY-MM-DD in the workspace's zone, with `to`."
        to:
          type: string
          description: The custom range's last day, YYYY-MM-DD, at or after `from` and at most 90 days after it.
    GetPlaytablePerformanceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            sid:
              type: string
            zone:
              type: string
              description: The workspace's IANA timezone; UTC when it has none.
            days:
              type: integer
            from:
              type: string
              description: "The window shown: its first day, YYYY-MM-DD in `zone`."
            to:
              type: string
              description: Its last day, both included.
            series:
              type: array
              items:
                type: object
                properties:
                  date:
                    type: string
                    description: The workspace's calendar day, YYYY-MM-DD.
                  added:
                    type: integer
                    description: People whose row was created that day.
                  reached:
                    type: integer
                    description: People first reached that day (a connection request, a message, an InMail or an email went out).
                  replied:
                    type: integer
                    description: People whose first reply at or after the first touch came that day.
                  positive:
                    type: integer
                    description: People first moved into a positive stage that day.
                  won:
                    type: integer
                    description: People first moved into Closed-Won that day.
                  won_value:
                    type: number
                    description: The deal sizes of the accounts whose first person was won that day.
                required:
                  - date
                  - added
                  - reached
                  - replied
                  - positive
                  - won
                  - won_value
              description: "2 x days days, oldest first: the window before the shown one, then the shown one."
            flow:
              type: object
              properties:
                people:
                  type: object
                  properties:
                    milestones:
                      type: array
                      items:
                        type: object
                        properties:
                          key:
                            type: string
                            enum:
                              - in_table
                              - reached
                              - engaged
                              - replied
                              - positive
                              - meeting
                              - won
                          count:
                            type: integer
                            minimum: 0
                            description: "Got at least this far (this step and every step beyond): count(M) = count(M+1) + sum(here) + sum(left)."
                          here:
                            type: object
                            additionalProperties:
                              type: integer
                              minimum: 0
                            description: Whose furthest step this is and who is still in progress, by current pipeline stage sid (cr_ps_; "none" = no stage).
                          left:
                            type: object
                            additionalProperties:
                              type: integer
                              minimum: 0
                            description: Whose furthest step this is and who left from it, by the exit stage they are on (a nurture, negative or disqualified stage sid).
                        required:
                          - key
                          - count
                          - here
                          - left
                  required:
                    - milestones
                accounts:
                  type: object
                  properties:
                    milestones:
                      type: array
                      items:
                        type: object
                        properties:
                          key:
                            type: string
                            enum:
                              - in_table
                              - reached
                              - engaged
                              - replied
                              - positive
                              - meeting
                              - won
                          count:
                            type: integer
                            minimum: 0
                            description: "Got at least this far (this step and every step beyond): count(M) = count(M+1) + sum(here) + sum(left)."
                          here:
                            type: object
                            additionalProperties:
                              type: integer
                              minimum: 0
                            description: Whose furthest step this is and who is still in progress, by current pipeline stage sid (cr_ps_; "none" = no stage).
                          left:
                            type: object
                            additionalProperties:
                              type: integer
                              minimum: 0
                            description: Whose furthest step this is and who left from it, by the exit stage they are on (a nurture, negative or disqualified stage sid).
                        required:
                          - key
                          - count
                          - here
                          - left
                  required:
                    - milestones
                  description: "The table's own accounts and every account its people work at: an account got as far as its furthest person in this table and left when its own stage is an exit."
              required:
                - people
                - accounts
            money:
              type: object
              properties:
                open_value:
                  type: number
                  description: Deal sizes of the accounts at Positive or Meeting, not won, not on an exit stage.
                open_accounts:
                  type: integer
                open_unpriced_accounts:
                  type: integer
                  description: Of the open accounts, the ones without a deal size.
                won_value:
                  type: number
                won_accounts:
                  type: integer
                won_priced_accounts:
                  type: integer
                lost_accounts:
                  type: integer
                  description: Accounts on a negative stage.
              required:
                - open_value
                - open_accounts
                - open_unpriced_accounts
                - won_value
                - won_accounts
                - won_priced_accounts
                - lost_accounts
            sources:
              type: array
              items:
                type: object
                properties:
                  data_source_sid:
                    type: string
                    nullable: true
                    description: ds_sc_; null = the people added by hand.
                  people:
                    type: integer
                  reached:
                    type: integer
                  engaged:
                    type: integer
                  replied:
                    type: integer
                  positive:
                    type: integer
                  won:
                    type: integer
                required:
                  - data_source_sid
                  - people
                  - reached
                  - engaged
                  - replied
                  - positive
                  - won
              description: The table's data sources, most people first, with how far their people got.
          required:
            - sid
            - zone
            - days
            - from
            - to
            - series
            - flow
            - money
            - sources
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    GetPlaytableResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            company_default_view_sid:
              type: string
              description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
            people_default_view_sid:
              type: string
              description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
              required:
                - auto_run
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - agent_sid
            - company_default_view_sid
            - people_default_view_sid
            - config
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        included:
          type: object
          properties:
            views:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: PlaytableViewDomain rows (1:N, default limit 50, created_at ASC) - see ./playtable_views.md.
            fields:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: PlaytableFieldDomain rows (1:N, default limit 100, created_at ASC) - see ./playtable_fields.md.
            data_sources_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
              description: "DataSourceCounts of the sources feeding the table (every live one, no view scope): total_count + groups by status / type / object_type - see ./data_sources.md."
            people_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                indexing_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
                - indexing_count
              description: "Reduced people count: total_count scoped to the people tab's DEFAULT VIEW filter (ES-served), indexing_count = the table's rows not in the index yet - see ./people.md."
            companies_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                indexing_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
                - indexing_count
              description: "Reduced company count: total_count scoped to the companies tab's DEFAULT VIEW filter (ES-served), indexing_count = the table's rows not in the index yet - see ./companies.md."
            workflows_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
              required:
                - total_count
              description: "WorkflowCounts of the workflows whose home is the table: total_count + groups.status - see ./workflows.md."
            outreach_counts:
              type: object
              properties:
                linkedin:
                  type: object
                  properties:
                    invited:
                      type: integer
                      minimum: 0
                    accepted:
                      type: integer
                      minimum: 0
                    messaged:
                      type: integer
                      minimum: 0
                    replied:
                      type: integer
                      minimum: 0
                  required:
                    - invited
                    - accepted
                    - messaged
                    - replied
                email:
                  type: object
                  properties:
                    emailed:
                      type: integer
                      minimum: 0
                    replied:
                      type: integer
                      minimum: 0
                  required:
                    - emailed
                    - replied
              required:
                - linkedin
                - email
              description: "PlaytableOutreachCounts (2026-09-26): those workflows' outreach counted in PEOPLE, per channel, the list's accept / reply rates. linkedin.invited / accepted: people a connection request went to / who accepted; linkedin.messaged: people a message reached (a message, an InMail, or the invite's note, which LinkedIn delivers as the thread's first message at the accept); linkedin.replied: people who answered at or after they were messaged; email.emailed / replied: the same by email. A rate is replied / messaged (emailed), people over people - see ./activities.md."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPlaytableRunResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            type:
              type: string
              enum:
                - enrich
                - export
                - import
                - bulk
            field_sids:
              type: array
              nullable: true
              items:
                type: string
            scope:
              type: object
              nullable: true
              properties:
                object_sids:
                  type: array
                  nullable: true
                  items:
                    type: string
                view_sid:
                  type: string
                  nullable: true
                filter:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: "Filter AST: and/or/not/any nodes (depth <= 5, root counts) over {field, op} leaves; op = >=1 of the §4.18 atoms; atoms AND."
              required:
                - object_sids
                - view_sid
                - filter
            params_snapshot:
              type: object
              nullable: true
              additionalProperties: {}
            max_budget:
              type: number
              nullable: true
            estimated_cost:
              type: number
              nullable: true
            file_url:
              type: string
              nullable: true
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            finished_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - type
            - field_sids
            - scope
            - params_snapshot
            - max_budget
            - estimated_cost
            - file_url
            - created_by
            - created_at
            - finished_at
        included:
          type: object
          properties:
            progress:
              type: object
              properties:
                state:
                  type: string
                  enum:
                    - waiting
                    - resolving
                    - queued
                    - running
                    - finished
                    - cancelled
                  description: "Derived - precedence: cancelled > finished > running > queued. Terminal: finished, cancelled."
                total_jobs:
                  type: number
                pending_jobs:
                  type: number
                processed_jobs:
                  type: number
                failed_jobs:
                  type: number
                cancelled_at:
                  type: string
                  nullable: true
                spent_credits:
                  type: number
              required:
                - state
                - total_jobs
                - pending_jobs
                - processed_jobs
                - failed_jobs
                - cancelled_at
                - spent_credits
              description: "1:1 derived progress (include[]=progress): state (queued|running|finished|cancelled), job counters from the Laravel batch, spent_credits from the ledger."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPlaytableViewResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
              description: View sid (pt_vw_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            playtable_sid:
              type: string
              description: Owner playtable (pt_tb_…).
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object tab the view lenses: people | company. Fixed at create."
            name:
              type: string
              description: View name; unique per (playtable, object_type) among live rows.
            columns:
              type: array
              items:
                type: object
                properties:
                  column_type:
                    type: string
                    enum:
                      - group
                      - field
                      - field_group
                    description: "'field' = custom field of the table; 'group' = built-in attribute group of the object."
                  column_value:
                    type: string
                    nullable: true
                    description: "For 'field': pt_fd_ sid of the custom field. For 'group': built-in attribute-group key of the object_type. null for 'field_group'."
                  column_values:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        column_value:
                          type: string
                        width:
                          type: integer
                        is_visible:
                          type: boolean
                      required:
                        - column_value
                        - width
                        - is_visible
                    description: "'field_group' only: the band's member fields in grid order."
                  is_collapsed:
                    type: boolean
                    nullable: true
                    description: "'field_group' only: the band folded to its tag."
                  column_name:
                    type: string
                    nullable: true
                    description: Header label override; null = catalog / field name.
                  is_pinned:
                    type: boolean
                    description: Pinned to the left edge of the grid.
                  width:
                    type: number
                    description: Column width in px (40..1000).
                  is_visible:
                    type: boolean
                    description: Hidden columns keep their slot and order.
                required:
                  - column_type
                  - column_value
                  - column_name
                  - is_pinned
                  - width
                  - is_visible
              description: Ordered left→right; [] = base-attribute catalog fallback.
            sort:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: Built-in object column ("created_at", "full_name") or "record.<slug>" custom-field reference.
                  direction:
                    type: string
                    enum:
                      - asc
                      - desc
                    description: "'asc' | 'desc'."
                required:
                  - field
                  - direction
              description: Applied in array order; max 3 entries.
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Stored filter AST (§4.18-atom tree); null = whole tab.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the view (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the view; null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - columns
            - sort
            - filter
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        included:
          type: object
          properties:
            playtable:
              type: object
              additionalProperties: {}
              description: Owner playtable row (PlaytableDomain - entities/playtables.md). Present when requested and found.
            workflow_sources:
              type: array
              items:
                type: object
                additionalProperties: {}
              description: Sources consuming this view as an audience (WorkflowSourceDomain - entities/workflow_sources.md); max 20, created_at DESC.
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetPlaytablesMetricsRequest:
      type: object
      description: Request body of `get_playtables_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Prefix-validated pt_tb_ sid(s).
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact match (dedup checks); substring matching goes through q.
            agent_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_ag_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_ag_
                is_null:
                  type: boolean
              additionalProperties: false
              description: The AI SDR the table picked (ub_ag_…); is_null:true = the tables on the team's default agent.
            q:
              type: string
              maxLength: 128
              description: Full-text LIKE (prefix/infix) over name + description.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: Required. Bounds only the *_added_count metrics; *_count totals are "now".
        group_by:
          type: string
          enum:
            - sid
          description: Per-table breakdown - one groups[] entry per playtable. Cap 500 groups. Mutually exclusive with group_by_field_sid.
        group_by_field_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_fd_
          description: scalar_select field sid - option distribution (field_value_groups[]). Requires filter.sid.eq = the field's playtable. Mutually exclusive with group_by.
      required:
        - period
    GetPlaytablesMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request PlaytableSearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Playtable rows matching the filter scope.
                    groups:
                      anyOf:
                        - type: object
                          additionalProperties: {}
                        - type: array
                          items: {}
                      description: Always empty - no group axes ('sid' is metrics-only). PHP empty map serialises as [].
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    people_count:
                      type: integer
                      minimum: 0
                      description: People whose playtable_sid is in the filter scope (now).
                    companies_count:
                      type: integer
                      minimum: 0
                      description: Companies whose playtable_sids[] intersects the scope (now, ES).
                    people_added_count:
                      type: integer
                      minimum: 0
                      description: People created within [period.from, period.to).
                    companies_added_count:
                      type: integer
                      minimum: 0
                      description: Companies created within the period (attach time is not stored; creation is the proxy - legacy semantics).
                    people_with_linkedin_count:
                      type: integer
                      minimum: 0
                      description: People with a LinkedIn identifier present (now); legacy have_linkedin.
                  required:
                    - people_count
                    - companies_count
                    - people_added_count
                    - companies_added_count
                    - people_with_linkedin_count
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: Playtable sid (pt_tb_…) - the group_by:'sid' axis.
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Playtable rows matching the filter scope.
                      groups:
                        anyOf:
                          - type: object
                            additionalProperties: {}
                          - type: array
                            items: {}
                        description: Always empty - no group axes ('sid' is metrics-only). PHP empty map serialises as [].
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      people_count:
                        type: integer
                        minimum: 0
                        description: People whose playtable_sid is in the filter scope (now).
                      companies_count:
                        type: integer
                        minimum: 0
                        description: Companies whose playtable_sids[] intersects the scope (now, ES).
                      people_added_count:
                        type: integer
                        minimum: 0
                        description: People created within [period.from, period.to).
                      companies_added_count:
                        type: integer
                        minimum: 0
                        description: Companies created within the period (attach time is not stored; creation is the proxy - legacy semantics).
                      people_with_linkedin_count:
                        type: integer
                        minimum: 0
                        description: People with a LinkedIn identifier present (now); legacy have_linkedin.
                    required:
                      - people_count
                      - companies_count
                      - people_added_count
                      - companies_added_count
                      - people_with_linkedin_count
                required:
                  - key
                  - counts
                  - metrics
              description: Present when group_by:'sid' - one entry per playtable.
            field_value_groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    nullable: true
                    description: Select option value; null = empty/unset cell.
                  objects_count:
                    type: integer
                    minimum: 0
                    description: Objects of the field's object_type carrying this value.
                required:
                  - key
                  - objects_count
              description: Present when group_by_field_sid is set.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetSenderProfilePerformanceRequest:
      type: object
      description: Request body of `get_sender_profile_performance`.
      properties:
        days:
          type: integer
          minimum: 1
          maximum: 90
          description: "The window in the workspace's days, today included (the drawer shows 30 by default; its 24 hours is 1, today). Either this or from + to, never both. The series covers twice as many days: this window and the one before it, to compare against."
        from:
          type: string
          description: "A custom range instead of `days`: its first day, YYYY-MM-DD in the workspace's zone, with `to`."
        to:
          type: string
          description: The custom range's last day, YYYY-MM-DD, at or after `from` and at most 90 days after it; the window before it is as long, for the comparison.
    GetSenderProfilePerformanceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            sid:
              type: string
              description: The sender profile (ub_sp_…).
            zone:
              type: string
              description: "The IANA timezone the days run in: the workspace's, UTC when unset."
            days:
              type: integer
            from:
              type: string
              description: "The window shown: its first day, YYYY-MM-DD in the zone."
            to:
              type: string
              description: "The window shown: its last day, YYYY-MM-DD in the zone (today for a `days` read)."
            caps:
              type: object
              properties:
                invites:
                  type: integer
                  nullable: true
                messages:
                  type: integer
                  nullable: true
                inmails:
                  type: integer
                  nullable: true
                emails:
                  type: integer
                  nullable: true
              required:
                - invites
                - messages
                - inmails
                - emails
              description: The sender profile's daily limits TODAY (the LinkedIn smart limits, the sum of the live mailboxes' limits); null where there is none. No history of the limits is kept.
            series:
              type: array
              items:
                type: object
                properties:
                  date:
                    type: string
                    description: The workspace's calendar day, YYYY-MM-DD.
                  invites:
                    type: integer
                    description: Connection requests the ledger sent (done tasks, by finished_at).
                  messages:
                    type: integer
                  inmails:
                    type: integer
                  emails:
                    type: integer
                  accepted:
                    type: integer
                    description: Connection requests accepted by people this sender profile invited.
                  notes_delivered:
                    type: integer
                    description: "Of those accepts, the ones that delivered the invite's note as the thread's first message (the accept fact's note_delivered, 2026-09-26): a message of this sender profile that no task sent, counted with `messages` as the base of the messages' reply rate."
                  linkedin_replies:
                    type: integer
                    description: People who replied on LinkedIn after this sender profile reached them, each once per window, on the day of their first reply in it.
                  message_replies:
                    type: integer
                    description: "People who answered a message of this sender profile (a reply at or after its first message to them: the first done message, or the accept that delivered the invite's note, whichever came first), once per window: the messages' reply rate against `messages` + `notes_delivered`. A reply to a note-less invite before any message is in linkedin_replies only."
                  inmail_replies:
                    type: integer
                    description: "People who answered an InMail of this sender profile (after its first InMail to them), once per window: the InMails' reply rate against `inmails`."
                  email_replies:
                    type: integer
                    description: The same, by email.
                  bounced:
                    type: integer
                    description: Emails that bounced, to people this sender profile emailed.
                  linkedin_positive:
                    type: integer
                    description: People moved into a positive pipeline stage after a reply to this sender profile, the latest before the move on LinkedIn; once per window, on the day of the move.
                  email_positive:
                    type: integer
                    description: The same, the latest reply by email.
                required:
                  - date
                  - invites
                  - messages
                  - inmails
                  - emails
                  - accepted
                  - notes_delivered
                  - linkedin_replies
                  - message_replies
                  - inmail_replies
                  - email_replies
                  - bounced
                  - linkedin_positive
                  - email_positive
              description: "2 x days days, oldest first, today last: the window before, then the window asked for."
            funnel:
              type: object
              properties:
                before:
                  type: object
                  properties:
                    linkedin:
                      type: object
                      properties:
                        reached:
                          type: integer
                          description: "LinkedIn: people a done invite, message or InMail went to in the window. Email: people emailed in it."
                        engaged:
                          type: integer
                          description: "LinkedIn: people who accepted in the window, of those the ledger invited. Email: the reached minus the ones whose email bounced in it (delivered)."
                        messaged:
                          type: integer
                          description: "LinkedIn: people a message or an InMail went to in the window, or whose accept delivered the invite's note in it. Email: the delivered (a delivered email is the message)."
                        replied:
                          type: integer
                          description: People who answered on the channel in the window, at or after the sender profile's first message-class touch of them, whenever that was.
                        positive:
                          type: integer
                          description: People moved into a positive pipeline stage in the window after a reply to this sender profile, the latest reply before the move on this channel.
                      required:
                        - reached
                        - engaged
                        - messaged
                        - replied
                        - positive
                    email:
                      type: object
                      properties:
                        reached:
                          type: integer
                          description: "LinkedIn: people a done invite, message or InMail went to in the window. Email: people emailed in it."
                        engaged:
                          type: integer
                          description: "LinkedIn: people who accepted in the window, of those the ledger invited. Email: the reached minus the ones whose email bounced in it (delivered)."
                        messaged:
                          type: integer
                          description: "LinkedIn: people a message or an InMail went to in the window, or whose accept delivered the invite's note in it. Email: the delivered (a delivered email is the message)."
                        replied:
                          type: integer
                          description: People who answered on the channel in the window, at or after the sender profile's first message-class touch of them, whenever that was.
                        positive:
                          type: integer
                          description: People moved into a positive pipeline stage in the window after a reply to this sender profile, the latest reply before the move on this channel.
                      required:
                        - reached
                        - engaged
                        - messaged
                        - replied
                        - positive
                  required:
                    - linkedin
                    - email
                shown:
                  type: object
                  properties:
                    linkedin:
                      type: object
                      properties:
                        reached:
                          type: integer
                          description: "LinkedIn: people a done invite, message or InMail went to in the window. Email: people emailed in it."
                        engaged:
                          type: integer
                          description: "LinkedIn: people who accepted in the window, of those the ledger invited. Email: the reached minus the ones whose email bounced in it (delivered)."
                        messaged:
                          type: integer
                          description: "LinkedIn: people a message or an InMail went to in the window, or whose accept delivered the invite's note in it. Email: the delivered (a delivered email is the message)."
                        replied:
                          type: integer
                          description: People who answered on the channel in the window, at or after the sender profile's first message-class touch of them, whenever that was.
                        positive:
                          type: integer
                          description: People moved into a positive pipeline stage in the window after a reply to this sender profile, the latest reply before the move on this channel.
                      required:
                        - reached
                        - engaged
                        - messaged
                        - replied
                        - positive
                    email:
                      type: object
                      properties:
                        reached:
                          type: integer
                          description: "LinkedIn: people a done invite, message or InMail went to in the window. Email: people emailed in it."
                        engaged:
                          type: integer
                          description: "LinkedIn: people who accepted in the window, of those the ledger invited. Email: the reached minus the ones whose email bounced in it (delivered)."
                        messaged:
                          type: integer
                          description: "LinkedIn: people a message or an InMail went to in the window, or whose accept delivered the invite's note in it. Email: the delivered (a delivered email is the message)."
                        replied:
                          type: integer
                          description: People who answered on the channel in the window, at or after the sender profile's first message-class touch of them, whenever that was.
                        positive:
                          type: integer
                          description: People moved into a positive pipeline stage in the window after a reply to this sender profile, the latest reply before the move on this channel.
                      required:
                        - reached
                        - engaged
                        - messaged
                        - replied
                        - positive
                  required:
                    - linkedin
                    - email
              required:
                - before
                - shown
              description: "The drawer's conversion board (2026-09-26): PEOPLE per stage and channel, for the window shown and the one before it, a person once per stage per window."
          required:
            - sid
            - zone
            - days
            - from
            - to
            - caps
            - series
            - funnel
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    GetWorkflowRecordsMetricsRequest:
      type: object
      description: Request body of `get_workflow_records_metrics`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_rc_
                  description: Workflow record sid (wf_rc_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_rc_
                    description: Workflow record sid (wf_rc_…).
              additionalProperties: false
              description: Prefix-validated wf_rc_ sid(s); also the single-row read (no get tool).
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: Progress-board scope (wf_wf_…).
            workflow_version_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_vr_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_vr_
              additionalProperties: false
              description: '"Who is still on the old version" (wf_vr_…).'
            people_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
              additionalProperties: false
              description: Person card (cr_pp_…); bulk ops take sids from people search first.
            entered_via_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_sr_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_sr_
              additionalProperties: false
              description: Per-source cohort (wf_sr_…).
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Per-sender load (ub_sp_…); is_null:true = unpinned (no send steps).
            current_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
              additionalProperties: false
              description: Step column of the board (int step id); meaningful only with a workflow_sid filter.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting_limit
                    - blocked
                    - active
                    - waiting
                    - paused_on_reply
                    - paused_manual
                    - paused_blocked
                    - failed
                    - completed
                    - exited
                ne:
                  type: string
                  enum:
                    - waiting_limit
                    - blocked
                    - active
                    - waiting
                    - paused_on_reply
                    - paused_manual
                    - paused_blocked
                    - failed
                    - completed
                    - exited
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting_limit
                      - blocked
                      - active
                      - waiting
                      - paused_on_reply
                      - paused_manual
                      - paused_blocked
                      - failed
                      - completed
                      - exited
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting_limit
                      - blocked
                      - active
                      - waiting
                      - paused_on_reply
                      - paused_manual
                      - paused_blocked
                      - failed
                      - completed
                      - exited
              additionalProperties: false
            last_touch_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Staleness - "no movement since …"; ISO 8601 bounds.
            finished_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "{ is_null: true } = live records; datetime bounds = terminal cohort."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Enrollment window; ISO 8601 bounds, combine in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows); set only by parent cascades."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: "Required. Period column: created_at (entered_count); outcome metrics clock on finished_at in the same window."
        group_by:
          type: string
          enum:
            - status
            - workflow_sid
            - current_step_id
            - sender_profile_sid
            - entered_via_source_sid
          description: Single axis - adds groups[] with per-value counts + metrics. current_step_id requires workflow_sid.eq in filter.
      required:
        - period
    GetWorkflowRecordsMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request WorkflowRecordSearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Records matching the filter scope.
                    groups:
                      type: object
                      properties:
                        status:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: The funnel axis - map keyed by the 8 WorkflowRecordStatusEnum values.
                        workflow_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: Per-workflow distribution across the team.
                        current_step_id:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: Board columns - keys are STRINGIFIED step ids; read with a workflow_sid filter in scope.
                        sender_profile_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: Per-sender load; "null" bucket = unpinned (no send steps).
                        entered_via_source_sid:
                          anyOf:
                            - type: object
                              additionalProperties:
                                type: number
                            - type: array
                              items: {}
                          description: Per-source funnel.
                      required:
                        - status
                        - workflow_sid
                        - current_step_id
                        - sender_profile_sid
                        - entered_via_source_sid
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    entered_count:
                      type: integer
                      minimum: 0
                      description: "Records enrolled in the window: created_at in [period.from, period.to)."
                    completed_count:
                      type: integer
                      minimum: 0
                      description: finished_at in period AND status = completed - sequences finished successfully.
                    failed_count:
                      type: integer
                      minimum: 0
                      description: "finished_at in period AND status = failed (a stoplist hit no longer fails a journey: it blocks it, paused_blocked, and is not in this count)."
                    exited_count:
                      type: integer
                      minimum: 0
                      description: finished_at in period AND status = exited - manual/system removals.
                    completion_rate:
                      type: number
                      nullable: true
                      minimum: 0
                      maximum: 1
                      description: completed_count / (completed + failed + exited in period); null when the denominator is 0.
                    avg_hours_to_complete:
                      type: number
                      nullable: true
                      description: AVG(finished_at - created_at) in hours over completed in period; null when none.
                  required:
                    - entered_count
                    - completed_count
                    - failed_count
                    - exited_count
                    - completion_rate
                    - avg_hours_to_complete
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    nullable: true
                    description: Value of the group_by axis (a status / workflow_sid / current_step_id / sender_profile_sid / entered_via_source_sid value); null = rows without a value on the axis (e.g. unpinned sender).
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Records matching the filter scope.
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: The funnel axis - map keyed by the 8 WorkflowRecordStatusEnum values.
                          workflow_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Per-workflow distribution across the team.
                          current_step_id:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Board columns - keys are STRINGIFIED step ids; read with a workflow_sid filter in scope.
                          sender_profile_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Per-sender load; "null" bucket = unpinned (no send steps).
                          entered_via_source_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Per-source funnel.
                        required:
                          - status
                          - workflow_sid
                          - current_step_id
                          - sender_profile_sid
                          - entered_via_source_sid
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      entered_count:
                        type: integer
                        minimum: 0
                        description: "Records enrolled in the window: created_at in [period.from, period.to)."
                      completed_count:
                        type: integer
                        minimum: 0
                        description: finished_at in period AND status = completed - sequences finished successfully.
                      failed_count:
                        type: integer
                        minimum: 0
                        description: "finished_at in period AND status = failed (a stoplist hit no longer fails a journey: it blocks it, paused_blocked, and is not in this count)."
                      exited_count:
                        type: integer
                        minimum: 0
                        description: finished_at in period AND status = exited - manual/system removals.
                      completion_rate:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 1
                        description: completed_count / (completed + failed + exited in period); null when the denominator is 0.
                      avg_hours_to_complete:
                        type: number
                        nullable: true
                        description: AVG(finished_at - created_at) in hours over completed in period; null when none.
                    required:
                      - entered_count
                      - completed_count
                      - failed_count
                      - exited_count
                      - completion_rate
                      - avg_hours_to_complete
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        included:
          type: object
          properties:
            published_version:
              type: object
              nullable: true
              properties:
                sid:
                  type: string
                  description: wf_vr_….
                workflow_sid:
                  type: string
                  description: wf_wf_… parent.
                version:
                  type: integer
                  description: Per-workflow sequence, >=1 (max+1 at publish).
                steps:
                  type: array
                  items:
                    oneOf:
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_connection_request
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          message:
                            type: string
                            nullable: true
                            description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_message
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          message:
                            type: string
                            minLength: 1
                            maxLength: 8000
                            description: Message template (same namespaces as all templates).
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - message
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_inmail
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          subject:
                            type: string
                            nullable: true
                            maxLength: 200
                          message:
                            type: string
                            minLength: 1
                            maxLength: 8000
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - message
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_visit_profile
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_endorse_skills
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          skills_count:
                            type: integer
                            minimum: 1
                            maximum: 10
                            description: Endorse the person's top N listed skills, 1..10.
                        required:
                          - type
                          - skills_count
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_withdraw_connection_request
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_like_latest_post
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_comment_latest_post
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          comment:
                            type: string
                            minLength: 1
                            maxLength: 1250
                            description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - comment
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - email_send
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          subject:
                            type: string
                            minLength: 1
                            maxLength: 255
                          body:
                            type: string
                            minLength: 1
                            maxLength: 100000
                            description: HTML body template.
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                          email_field:
                            type: string
                            nullable: true
                            description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                          cc:
                            type: array
                            nullable: true
                            items:
                              type: string
                              maxLength: 320
                              format: email
                            maxItems: 5
                            description: Up to 5 literal copy addresses.
                          bcc:
                            type: array
                            nullable: true
                            items:
                              type: string
                              maxLength: 320
                              format: email
                            maxItems: 5
                            description: Up to 5 literal blind-copy addresses.
                          attachments:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                sid:
                                  type: string
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^wf_at_
                                name:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                              required:
                                - sid
                                - name
                              additionalProperties: false
                            maxItems: 5
                            description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                          reply_in_thread:
                            type: boolean
                            nullable: true
                          track_opens:
                            type: boolean
                            nullable: true
                          track_clicks:
                            type: boolean
                            nullable: true
                          unsubscribe_link:
                            type: boolean
                            nullable: true
                        required:
                          - type
                          - subject
                          - body
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - wait
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          for:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                        required:
                          - type
                          - for
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - wait_for_event
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          event:
                            type: string
                            enum:
                              - linkedin_connection_request_accepted
                              - email_opened
                              - email_link_clicked
                            description: Event observed via the activities ingest.
                          timeout:
                            type: object
                            properties:
                              after:
                                type: string
                                pattern: ^[1-9][0-9]*[mhd]$
                                description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                              steps:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - after
                              - steps
                            additionalProperties: false
                            description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                        required:
                          - type
                          - event
                          - timeout
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - condition
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                                label:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor caption.
                                when:
                                  type: object
                                  additionalProperties: {}
                                  description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                                steps:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - when
                                - steps
                              additionalProperties: false
                            minItems: 1
                            maxItems: 9
                            description: 1..9 branches, evaluated in order, first match wins.
                          else:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - type
                          - branches
                          - else
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - ab_test
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                                label:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor caption ("Variant A").
                                weight:
                                  type: integer
                                  minimum: 1
                                  description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                                steps:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - weight
                                - steps
                              additionalProperties: false
                            minItems: 2
                            maxItems: 9
                            description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                        required:
                          - type
                          - branches
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - end
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - api_call
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          method:
                            type: string
                            enum:
                              - GET
                              - POST
                              - PUT
                              - PATCH
                              - DELETE
                          url:
                            type: string
                            minLength: 1
                            maxLength: 2048
                            description: https-only (publish check); a template - variables may stand in the path and the query.
                          headers:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: string
                              maxLength: 1024
                          query:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: string
                              maxLength: 2048
                          body:
                            type: string
                            nullable: true
                            maxLength: 16000
                            description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                          provider_connection_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^in_cn_
                            description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                          timeout_secs:
                            type: integer
                            nullable: true
                            minimum: 1
                            maximum: 120
                          retry_on_error:
                            type: boolean
                            nullable: true
                          remove_empty_values:
                            type: boolean
                            nullable: true
                          output_key:
                            type: string
                            nullable: true
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                        required:
                          - type
                          - method
                          - url
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - ask_ai
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          prompt:
                            type: string
                            minLength: 1
                            maxLength: 8000
                            description: Same variable namespaces as message templates.
                          output_key:
                            type: string
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                          preset_sid:
                            type: string
                            nullable: true
                            description: gtm-api preset for the AI call; null = team default.
                        required:
                          - type
                          - prompt
                          - output_key
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - manual_task
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          title:
                            type: string
                            minLength: 1
                            maxLength: 255
                          instructions:
                            type: string
                            nullable: true
                            maxLength: 4000
                            description: Rendered into the human todo; the journey waits until the task is completed.
                        required:
                          - type
                          - title
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - move_to_workflow
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          target_workflow_sid:
                            type: string
                            minLength: 18
                            maxLength: 18
                            pattern: ^wf_wf_
                            description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                          mode:
                            type: string
                            nullable: true
                            enum:
                              - from_start
                              - from_current
                            description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                        required:
                          - type
                          - target_workflow_sid
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - add_tag
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          tag_sids:
                            type: array
                            items:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^cr_tg_
                            minItems: 1
                            maxItems: 20
                            description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                        required:
                          - type
                          - tag_sids
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - remove_tag
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          tag_sids:
                            type: array
                            items:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^cr_tg_
                            minItems: 1
                            maxItems: 20
                            description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                        required:
                          - type
                          - tag_sids
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - set_field
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          field_slug:
                            type: string
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                          value:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                              - {}
                              - {}
                            description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                        required:
                          - type
                          - field_slug
                          - value
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - change_sender
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          sender_profile_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^ub_sp_
                            description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                          rotation:
                            type: string
                            nullable: true
                            enum:
                              - fair
                              - random
                              - new_sender
                              - prior_engagement
                            description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                        required:
                          - type
                        additionalProperties: false
                  description: Immutable snapshot of the step document at publish.
                steps_count:
                  type: integer
                  description: Denormalized total step count (incl. nested).
                entry_step_id:
                  type: integer
                  description: = steps[0].id - enrollment starts here.
                created_at:
                  type: string
                  description: ISO 8601 UTC - publish moment.
              required:
                - sid
                - workflow_sid
                - version
                - steps
                - steps_count
                - entry_step_id
                - created_at
              description: WorkflowVersionDomain (1:1 via published_version_sid; heavy - full steps JSON) - see ./workflow_versions.md.
            sources:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                required:
                  - sid
              description: WorkflowSourceDomain audience feeds (1:N, default 50, created_at ASC) - see ./workflow_sources.md.
            records_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                groups:
                  type: object
                  properties:
                    status:
                      anyOf:
                        - type: object
                          additionalProperties:
                            type: number
                        - type: array
                          items: {}
                      description: "Journey funnel by WorkflowRecordStatusEnum: waiting_limit / blocked / active / waiting / paused_on_reply / paused_manual / paused_blocked / failed / completed / exited."
                  required:
                    - status
              required:
                - total_count
                - groups
              description: "WorkflowRecordCounts over { workflow_sid: parent.sid } - the full-scope enrolled/active/replied/done snapshot for the editor header (§4.17a) - see ./workflow_records.md."
            forecast:
              type: object
              nullable: true
              properties:
                scheduled_count:
                  type: integer
                  minimum: 0
                  description: Send-class tasks scheduled on a sender profile.
                sender_profiles_count:
                  type: integer
                  minimum: 0
                days_to_drain:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Days from today until the last planned send leaves (1 = everything today); null when nothing is planned.
                drains_on:
                  type: string
                  nullable: true
                  description: YYYY-MM-DD (UTC) of the last send; null past the horizon.
                over_horizon:
                  type: boolean
                  description: 'The walk stopped at a year: read "over a year".'
                buckets:
                  type: array
                  items:
                    type: object
                    properties:
                      sender_profile_sid:
                        type: string
                      type:
                        type: string
                        description: The send-class task type.
                      scheduled_count:
                        type: integer
                        minimum: 0
                      daily_share:
                        type: integer
                        minimum: 0
                        description: This workflow's share of the (sender profile, type) daily cap, by priority (the sender profile pick's split).
                      days_to_drain:
                        type: integer
                        minimum: 0
                      over_horizon:
                        type: boolean
                    required:
                      - sender_profile_sid
                      - type
                      - scheduled_count
                      - daily_share
                      - days_to_drain
                      - over_horizon
                timeline:
                  type: array
                  items:
                    type: object
                    properties:
                      day:
                        type: string
                        description: YYYY-MM-DD, UTC.
                      planned:
                        type: integer
                        minimum: 0
                      by_type:
                        type: object
                        additionalProperties:
                          type: integer
                          minimum: 0
                    required:
                      - day
                      - planned
                      - by_type
                  description: The first 60 days; every bucket added up per day.
              required:
                - scheduled_count
                - sender_profiles_count
                - days_to_drain
                - drains_on
                - over_horizon
                - buckets
                - timeline
              description: "How long the planned sends take at the current limits (TASK_EXECUTION_ARCHITECTURE.md §6.5, D41): the scheduled tasks per (sender profile, type) laid over the days ahead at the workflow's priority share of the sender profile's daily cap, closed days skipped. Computed on read from counts, never stored; rows held at the door are not in it."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetWorkflowVersionResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - get
        item:
          type: object
          properties:
            sid:
              type: string
              description: Version sid (wf_vr_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              description: Parent workflow (wf_wf_…) - written once at publish, never repointed; see ./workflows.md.
            version:
              type: integer
              minimum: 1
              description: Per-workflow sequence, max+1 at publish (serialized by the publish FOR UPDATE on the workflow row).
            steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      message:
                        type: string
                        nullable: true
                        description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                        description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                    required:
                      - id
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                    required:
                      - id
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                        description: InMail subject template, max 200.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: InMail body template, 1..8000.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                    required:
                      - id
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                    required:
                      - id
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                    required:
                      - id
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                    required:
                      - id
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                    required:
                      - id
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                        description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                    required:
                      - id
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - email_send
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                        description: Email subject template, 1..255.
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: Email body template, HTML, 1..100000.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                              description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                              description: The filename the receiver sees.
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                      reply_in_thread:
                        type: boolean
                        nullable: true
                        description: True threads the send onto the prior email exchange.
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - id
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      type:
                        type: string
                        enum:
                          - wait
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                    required:
                      - id
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event a wait_for_event step blocks on (observed via activities ingest).
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*(m|h|d)$
                            description: "Timeout duration - bundled: a timeout path cannot exist without one."
                          steps:
                            type: array
                            items:
                              oneOf:
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_send_connection_request
                                    message:
                                      type: string
                                      nullable: true
                                      description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                                    required_fields:
                                      type: object
                                      nullable: true
                                      properties:
                                        refs:
                                          type: array
                                          items:
                                            type: string
                                            maxLength: 160
                                            pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                          maxItems: 20
                                          description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                        on_missing:
                                          type: string
                                          enum:
                                            - fail
                                            - skip
                                          description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                      required:
                                        - refs
                                        - on_missing
                                      additionalProperties: false
                                      description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_send_message
                                    message:
                                      type: string
                                      minLength: 1
                                      maxLength: 8000
                                      description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                                    required_fields:
                                      type: object
                                      nullable: true
                                      properties:
                                        refs:
                                          type: array
                                          items:
                                            type: string
                                            maxLength: 160
                                            pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                          maxItems: 20
                                          description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                        on_missing:
                                          type: string
                                          enum:
                                            - fail
                                            - skip
                                          description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                      required:
                                        - refs
                                        - on_missing
                                      additionalProperties: false
                                      description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                  required:
                                    - id
                                    - type
                                    - message
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_send_inmail
                                    subject:
                                      type: string
                                      nullable: true
                                      maxLength: 200
                                      description: InMail subject template, max 200.
                                    message:
                                      type: string
                                      minLength: 1
                                      maxLength: 8000
                                      description: InMail body template, 1..8000.
                                    required_fields:
                                      type: object
                                      nullable: true
                                      properties:
                                        refs:
                                          type: array
                                          items:
                                            type: string
                                            maxLength: 160
                                            pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                          maxItems: 20
                                          description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                        on_missing:
                                          type: string
                                          enum:
                                            - fail
                                            - skip
                                          description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                      required:
                                        - refs
                                        - on_missing
                                      additionalProperties: false
                                      description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                  required:
                                    - id
                                    - type
                                    - message
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_visit_profile
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_endorse_skills
                                    skills_count:
                                      type: integer
                                      minimum: 1
                                      maximum: 10
                                      description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                                  required:
                                    - id
                                    - type
                                    - skills_count
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_withdraw_connection_request
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_like_latest_post
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - linkedin_comment_latest_post
                                    comment:
                                      type: string
                                      minLength: 1
                                      maxLength: 1250
                                      description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                                    required_fields:
                                      type: object
                                      nullable: true
                                      properties:
                                        refs:
                                          type: array
                                          items:
                                            type: string
                                            maxLength: 160
                                            pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                          maxItems: 20
                                          description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                        on_missing:
                                          type: string
                                          enum:
                                            - fail
                                            - skip
                                          description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                      required:
                                        - refs
                                        - on_missing
                                      additionalProperties: false
                                      description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                                  required:
                                    - id
                                    - type
                                    - comment
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - email_send
                                    subject:
                                      type: string
                                      minLength: 1
                                      maxLength: 255
                                      description: Email subject template, 1..255.
                                    body:
                                      type: string
                                      minLength: 1
                                      maxLength: 100000
                                      description: Email body template, HTML, 1..100000.
                                    required_fields:
                                      type: object
                                      nullable: true
                                      properties:
                                        refs:
                                          type: array
                                          items:
                                            type: string
                                            maxLength: 160
                                            pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                          maxItems: 20
                                          description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                        on_missing:
                                          type: string
                                          enum:
                                            - fail
                                            - skip
                                          description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                      required:
                                        - refs
                                        - on_missing
                                      additionalProperties: false
                                      description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                    email_field:
                                      type: string
                                      nullable: true
                                      description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                                    cc:
                                      type: array
                                      nullable: true
                                      items:
                                        type: string
                                        maxLength: 320
                                        format: email
                                      maxItems: 5
                                      description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                                    bcc:
                                      type: array
                                      nullable: true
                                      items:
                                        type: string
                                        maxLength: 320
                                        format: email
                                      maxItems: 5
                                      description: Up to 5 literal blind-copy addresses.
                                    attachments:
                                      type: array
                                      nullable: true
                                      items:
                                        type: object
                                        properties:
                                          sid:
                                            type: string
                                            minLength: 18
                                            maxLength: 18
                                            pattern: ^wf_at_
                                            description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                                          name:
                                            type: string
                                            minLength: 1
                                            maxLength: 255
                                            description: The filename the receiver sees.
                                        required:
                                          - sid
                                          - name
                                        additionalProperties: false
                                      maxItems: 5
                                      description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                                    reply_in_thread:
                                      type: boolean
                                      nullable: true
                                      description: True threads the send onto the prior email exchange.
                                    track_opens:
                                      type: boolean
                                      nullable: true
                                    track_clicks:
                                      type: boolean
                                      nullable: true
                                    unsubscribe_link:
                                      type: boolean
                                      nullable: true
                                  required:
                                    - id
                                    - type
                                    - subject
                                    - body
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    type:
                                      type: string
                                      enum:
                                        - wait
                                    for:
                                      type: string
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                                  required:
                                    - id
                                    - type
                                    - for
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    type:
                                      type: string
                                      enum:
                                        - wait_for_event
                                    event:
                                      type: string
                                      enum:
                                        - linkedin_connection_request_accepted
                                        - email_opened
                                        - email_link_clicked
                                      description: Event a wait_for_event step blocks on (observed via activities ingest).
                                    timeout:
                                      type: object
                                      properties:
                                        after:
                                          type: string
                                          pattern: ^[1-9][0-9]*(m|h|d)$
                                          description: "Timeout duration - bundled: a timeout path cannot exist without one."
                                        steps:
                                          type: array
                                          items:
                                            type: object
                                            additionalProperties: {}
                                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                          description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                                      required:
                                        - after
                                        - steps
                                      additionalProperties: false
                                      description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                                  required:
                                    - id
                                    - type
                                    - event
                                    - timeout
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - condition
                                    branches:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                      minItems: 1
                                      maxItems: 9
                                      description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                                    else:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                      description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                                  required:
                                    - id
                                    - type
                                    - branches
                                    - else
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - ab_test
                                    branches:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                      minItems: 2
                                      maxItems: 9
                                      description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                                  required:
                                    - id
                                    - type
                                    - branches
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    type:
                                      type: string
                                      enum:
                                        - end
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - api_call
                                    method:
                                      type: string
                                      enum:
                                        - GET
                                        - POST
                                        - PUT
                                        - PATCH
                                        - DELETE
                                      description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                                    url:
                                      type: string
                                      minLength: 1
                                      maxLength: 2048
                                      description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                                    headers:
                                      type: object
                                      nullable: true
                                      additionalProperties:
                                        type: string
                                        maxLength: 1024
                                      description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                                    query:
                                      type: object
                                      nullable: true
                                      additionalProperties:
                                        type: string
                                        maxLength: 2048
                                      description: Up to 20 query parameters appended to the URL; values are templates.
                                    body:
                                      type: string
                                      nullable: true
                                      maxLength: 16000
                                      description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                                    provider_connection_sid:
                                      type: string
                                      nullable: true
                                      minLength: 18
                                      maxLength: 18
                                      pattern: ^in_cn_
                                      description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                                    timeout_secs:
                                      type: integer
                                      nullable: true
                                      minimum: 1
                                      maximum: 120
                                      description: The call budget in seconds; null = 15.
                                    retry_on_error:
                                      type: boolean
                                      nullable: true
                                      description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                                    remove_empty_values:
                                      type: boolean
                                      nullable: true
                                      description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                                    output_key:
                                      type: string
                                      nullable: true
                                      pattern: ^[a-z][a-z0-9_]{0,63}$
                                      description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                                  required:
                                    - id
                                    - type
                                    - method
                                    - url
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - ask_ai
                                    prompt:
                                      type: string
                                      minLength: 1
                                      maxLength: 8000
                                      description: Prompt template, 1..8000 - same variable namespaces as message templates.
                                    output_key:
                                      type: string
                                      pattern: ^[a-z][a-z0-9_]{0,63}$
                                      description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                                    preset_sid:
                                      type: string
                                      nullable: true
                                      description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                                  required:
                                    - id
                                    - type
                                    - prompt
                                    - output_key
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    type:
                                      type: string
                                      enum:
                                        - manual_task
                                    title:
                                      type: string
                                      minLength: 1
                                      maxLength: 255
                                      description: Todo title template, 1..255.
                                    instructions:
                                      type: string
                                      nullable: true
                                      maxLength: 4000
                                      description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                                  required:
                                    - id
                                    - type
                                    - title
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - move_to_workflow
                                    target_workflow_sid:
                                      type: string
                                      minLength: 18
                                      maxLength: 18
                                      pattern: ^wf_wf_
                                      description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                                    mode:
                                      type: string
                                      nullable: true
                                      enum:
                                        - from_start
                                        - from_current
                                      description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                                  required:
                                    - id
                                    - type
                                    - target_workflow_sid
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - add_tag
                                    tag_sids:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^cr_tg_
                                        description: CRM tag sid (cr_tg_…).
                                      minItems: 1
                                      maxItems: 20
                                      description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                                  required:
                                    - id
                                    - type
                                    - tag_sids
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - remove_tag
                                    tag_sids:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^cr_tg_
                                        description: CRM tag sid (cr_tg_…).
                                      minItems: 1
                                      maxItems: 20
                                      description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                                  required:
                                    - id
                                    - type
                                    - tag_sids
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - set_field
                                    field_slug:
                                      type: string
                                      pattern: ^[a-z][a-z0-9_]{0,63}$
                                      description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                                    value:
                                      anyOf:
                                        - type: string
                                        - type: number
                                        - type: boolean
                                        - {}
                                        - {}
                                      description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                                  required:
                                    - id
                                    - type
                                    - field_slug
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    id:
                                      type: integer
                                      minimum: 1
                                      description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                    name:
                                      type: string
                                      nullable: true
                                      maxLength: 255
                                      description: Editor label.
                                    delay:
                                      type: string
                                      nullable: true
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                    type:
                                      type: string
                                      enum:
                                        - change_sender
                                    sender_profile_sid:
                                      type: string
                                      nullable: true
                                      minLength: 18
                                      maxLength: 18
                                      pattern: ^ub_sp_
                                      description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                                    rotation:
                                      type: string
                                      nullable: true
                                      enum:
                                        - fair
                                        - random
                                        - new_sender
                                        - prior_engagement
                                      description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                                    rotations:
                                      type: array
                                      nullable: true
                                      items:
                                        type: object
                                        properties:
                                          sender_profile_sid:
                                            type: string
                                            nullable: true
                                            minLength: 18
                                            maxLength: 18
                                            pattern: ^ub_sp_
                                            description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                                          entry_step_id:
                                            type: integer
                                            nullable: true
                                            minimum: 0
                                            exclusiveMinimum: true
                                            description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                                        required:
                                          - sender_profile_sid
                                          - entry_step_id
                                        additionalProperties: false
                                      minItems: 1
                                      maxItems: 10
                                      description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                                  required:
                                    - id
                                    - type
                                  additionalProperties: false
                            description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                    required:
                      - id
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - condition
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            steps:
                              type: array
                              items:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              description: Branch sub-flow; falls through to the condition's successor unless it ends with `end`.
                          required:
                            - id
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                      else:
                        type: array
                        items:
                          oneOf:
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_connection_request
                                message:
                                  type: string
                                  nullable: true
                                  description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                  description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                              required:
                                - id
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_message
                                message:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                  description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                  description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                              required:
                                - id
                                - type
                                - message
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_inmail
                                subject:
                                  type: string
                                  nullable: true
                                  maxLength: 200
                                  description: InMail subject template, max 200.
                                message:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                  description: InMail body template, 1..8000.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                  description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                              required:
                                - id
                                - type
                                - message
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_visit_profile
                              required:
                                - id
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_endorse_skills
                                skills_count:
                                  type: integer
                                  minimum: 1
                                  maximum: 10
                                  description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                              required:
                                - id
                                - type
                                - skills_count
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_withdraw_connection_request
                              required:
                                - id
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_like_latest_post
                              required:
                                - id
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - linkedin_comment_latest_post
                                comment:
                                  type: string
                                  minLength: 1
                                  maxLength: 1250
                                  description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                  description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                              required:
                                - id
                                - type
                                - comment
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - email_send
                                subject:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                                  description: Email subject template, 1..255.
                                body:
                                  type: string
                                  minLength: 1
                                  maxLength: 100000
                                  description: Email body template, HTML, 1..100000.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                  description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                email_field:
                                  type: string
                                  nullable: true
                                  description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                                cc:
                                  type: array
                                  nullable: true
                                  items:
                                    type: string
                                    maxLength: 320
                                    format: email
                                  maxItems: 5
                                  description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                                bcc:
                                  type: array
                                  nullable: true
                                  items:
                                    type: string
                                    maxLength: 320
                                    format: email
                                  maxItems: 5
                                  description: Up to 5 literal blind-copy addresses.
                                attachments:
                                  type: array
                                  nullable: true
                                  items:
                                    type: object
                                    properties:
                                      sid:
                                        type: string
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^wf_at_
                                        description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                                      name:
                                        type: string
                                        minLength: 1
                                        maxLength: 255
                                        description: The filename the receiver sees.
                                    required:
                                      - sid
                                      - name
                                    additionalProperties: false
                                  maxItems: 5
                                  description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                                reply_in_thread:
                                  type: boolean
                                  nullable: true
                                  description: True threads the send onto the prior email exchange.
                                track_opens:
                                  type: boolean
                                  nullable: true
                                track_clicks:
                                  type: boolean
                                  nullable: true
                                unsubscribe_link:
                                  type: boolean
                                  nullable: true
                              required:
                                - id
                                - type
                                - subject
                                - body
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                type:
                                  type: string
                                  enum:
                                    - wait
                                for:
                                  type: string
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                              required:
                                - id
                                - type
                                - for
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                type:
                                  type: string
                                  enum:
                                    - wait_for_event
                                event:
                                  type: string
                                  enum:
                                    - linkedin_connection_request_accepted
                                    - email_opened
                                    - email_link_clicked
                                  description: Event a wait_for_event step blocks on (observed via activities ingest).
                                timeout:
                                  type: object
                                  properties:
                                    after:
                                      type: string
                                      pattern: ^[1-9][0-9]*(m|h|d)$
                                      description: "Timeout duration - bundled: a timeout path cannot exist without one."
                                    steps:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                      description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                                  required:
                                    - after
                                    - steps
                                  additionalProperties: false
                                  description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                              required:
                                - id
                                - type
                                - event
                                - timeout
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - condition
                                branches:
                                  type: array
                                  items:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                  minItems: 1
                                  maxItems: 9
                                  description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                                else:
                                  type: array
                                  items:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                  description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                              required:
                                - id
                                - type
                                - branches
                                - else
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - ab_test
                                branches:
                                  type: array
                                  items:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                  minItems: 2
                                  maxItems: 9
                                  description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                              required:
                                - id
                                - type
                                - branches
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                type:
                                  type: string
                                  enum:
                                    - end
                              required:
                                - id
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - api_call
                                method:
                                  type: string
                                  enum:
                                    - GET
                                    - POST
                                    - PUT
                                    - PATCH
                                    - DELETE
                                  description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                                url:
                                  type: string
                                  minLength: 1
                                  maxLength: 2048
                                  description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                                headers:
                                  type: object
                                  nullable: true
                                  additionalProperties:
                                    type: string
                                    maxLength: 1024
                                  description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                                query:
                                  type: object
                                  nullable: true
                                  additionalProperties:
                                    type: string
                                    maxLength: 2048
                                  description: Up to 20 query parameters appended to the URL; values are templates.
                                body:
                                  type: string
                                  nullable: true
                                  maxLength: 16000
                                  description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                                provider_connection_sid:
                                  type: string
                                  nullable: true
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^in_cn_
                                  description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                                timeout_secs:
                                  type: integer
                                  nullable: true
                                  minimum: 1
                                  maximum: 120
                                  description: The call budget in seconds; null = 15.
                                retry_on_error:
                                  type: boolean
                                  nullable: true
                                  description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                                remove_empty_values:
                                  type: boolean
                                  nullable: true
                                  description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                                output_key:
                                  type: string
                                  nullable: true
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                              required:
                                - id
                                - type
                                - method
                                - url
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - ask_ai
                                prompt:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                  description: Prompt template, 1..8000 - same variable namespaces as message templates.
                                output_key:
                                  type: string
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                                preset_sid:
                                  type: string
                                  nullable: true
                                  description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                              required:
                                - id
                                - type
                                - prompt
                                - output_key
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                type:
                                  type: string
                                  enum:
                                    - manual_task
                                title:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                                  description: Todo title template, 1..255.
                                instructions:
                                  type: string
                                  nullable: true
                                  maxLength: 4000
                                  description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                              required:
                                - id
                                - type
                                - title
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - move_to_workflow
                                target_workflow_sid:
                                  type: string
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^wf_wf_
                                  description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                                mode:
                                  type: string
                                  nullable: true
                                  enum:
                                    - from_start
                                    - from_current
                                  description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                              required:
                                - id
                                - type
                                - target_workflow_sid
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - add_tag
                                tag_sids:
                                  type: array
                                  items:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^cr_tg_
                                    description: CRM tag sid (cr_tg_…).
                                  minItems: 1
                                  maxItems: 20
                                  description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                              required:
                                - id
                                - type
                                - tag_sids
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - remove_tag
                                tag_sids:
                                  type: array
                                  items:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^cr_tg_
                                    description: CRM tag sid (cr_tg_…).
                                  minItems: 1
                                  maxItems: 20
                                  description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                              required:
                                - id
                                - type
                                - tag_sids
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - set_field
                                field_slug:
                                  type: string
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                                value:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                    - {}
                                    - {}
                                  description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                              required:
                                - id
                                - type
                                - field_slug
                                - value
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                delay:
                                  type: string
                                  nullable: true
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                type:
                                  type: string
                                  enum:
                                    - change_sender
                                sender_profile_sid:
                                  type: string
                                  nullable: true
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^ub_sp_
                                  description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                                rotation:
                                  type: string
                                  nullable: true
                                  enum:
                                    - fair
                                    - random
                                    - new_sender
                                    - prior_engagement
                                  description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                                rotations:
                                  type: array
                                  nullable: true
                                  items:
                                    type: object
                                    properties:
                                      sender_profile_sid:
                                        type: string
                                        nullable: true
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^ub_sp_
                                        description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                                      entry_step_id:
                                        type: integer
                                        nullable: true
                                        minimum: 0
                                        exclusiveMinimum: true
                                        description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                                    required:
                                      - sender_profile_sid
                                      - entry_step_id
                                    additionalProperties: false
                                  minItems: 1
                                  maxItems: 10
                                  description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                              required:
                                - id
                                - type
                              additionalProperties: false
                        description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                    required:
                      - id
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - ab_test
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights), first arm whose cumulative range contains it (workflow_versions.md ab_test algorithm).
                            steps:
                              type: array
                              items:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              description: Arm sub-flow; falls through to the ab_test successor unless it ends with `end`.
                          required:
                            - id
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                    required:
                      - id
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      type:
                        type: string
                        enum:
                          - end
                    required:
                      - id
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - api_call
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                        description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                        description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                        description: Up to 20 query parameters appended to the URL; values are templates.
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                        description: The call budget in seconds; null = 15.
                      retry_on_error:
                        type: boolean
                        nullable: true
                        description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                      remove_empty_values:
                        type: boolean
                        nullable: true
                        description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                    required:
                      - id
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - ask_ai
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Prompt template, 1..8000 - same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                    required:
                      - id
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      type:
                        type: string
                        enum:
                          - manual_task
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                        description: Todo title template, 1..255.
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                    required:
                      - id
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - id
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - add_tag
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                          description: CRM tag sid (cr_tg_…).
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                    required:
                      - id
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - remove_tag
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                          description: CRM tag sid (cr_tg_…).
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - id
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - set_field
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                    required:
                      - id
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      delay:
                        type: string
                        nullable: true
                        pattern: ^[1-9][0-9]*(m|h|d)$
                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                      type:
                        type: string
                        enum:
                          - change_sender
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                      rotations:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sender_profile_sid:
                              type: string
                              nullable: true
                              minLength: 18
                              maxLength: 18
                              pattern: ^ub_sp_
                              description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                            entry_step_id:
                              type: integer
                              nullable: true
                              minimum: 0
                              exclusiveMinimum: true
                              description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                          required:
                            - sender_profile_sid
                            - entry_step_id
                          additionalProperties: false
                        minItems: 1
                        maxItems: 10
                        description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                    required:
                      - id
                      - type
                    additionalProperties: false
              minItems: 1
              maxItems: 100
              description: "Immutable chain-and-blocks snapshot: array order = execution order, entry = steps[0], root-array exhaustion completes the record; 1..100 steps TOTAL incl. nested, <=512 KB serialized. Step ids are stable across versions."
            steps_count:
              type: integer
              minimum: 1
              maximum: 100
              description: Denormalized total step count (incl. nested) at insert - lets lists/events skip the JSON.
            entry_step_id:
              type: integer
              minimum: 1
              description: = steps[0].id, denormalized at publish; every enrollment starts here.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: The PUBLISHER - actor of workflows.publish; answers "who shipped v7".
            created_at:
              type: string
              description: "ISO 8601 UTC - the publish moment. No updated_at: the row never changes."
          required:
            - sid
            - team_sid
            - workflow_sid
            - version
            - steps
            - steps_count
            - entry_step_id
            - created_by
            - created_at
        included:
          type: object
          properties:
            workflow:
              type: object
              properties:
                sid:
                  type: string
                name:
                  type: string
                status:
                  type: string
                published_version_sid:
                  type: string
                  nullable: true
              required:
                - sid
                - name
                - status
                - published_version_sid
              description: "Parent workflow (WorkflowDomain - entities/workflows.md): name/status + published_version_sid to check whether THIS row is the live pointer."
            workflow_records_counts:
              type: object
              properties:
                total_count:
                  type: integer
                  minimum: 0
                  description: Records pinned to this version.
                groups:
                  type: object
                  properties:
                    status:
                      anyOf:
                        - type: object
                          additionalProperties:
                            type: integer
                            minimum: 0
                        - type: array
                          items: {}
                      description: Funnel by WorkflowRecordStatusEnum - non-terminal buckets = "who is still running this version".
                  required:
                    - status
                  description: Axes per WorkflowRecordGroupableFieldsEnum (canonical shape - entities/workflow_records.md). PHP empty map serialises as [].
              required:
                - total_count
                - groups
              description: "Parent-include counts (§4.17) computed against {workflow_version_sid: parent.sid}: how many records are pinned to this version and in which statuses, without loading rows."
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - included
        - includes
        - meta
    GetWorkflowsMetricsRequest:
      type: object
      description: Request body of `get_workflows_metrics`.
      properties:
        filter:
          type: object
          properties:
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: The home playtable.
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: Workflow sid (wf_wf_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Workflow sid (wf_wf_…).
              additionalProperties: false
              description: Prefix-validated wf_wf_ sid(s).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - archived
                ne:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - archived
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - archived
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - archived
              additionalProperties: false
              description: Default UI scope excludes archived client-side.
            published_version_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_vr_
                is_null:
                  type: boolean
              additionalProperties: false
              description: is_null:true = never published.
            agent_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_ag_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_ag_
                is_null:
                  type: boolean
              additionalProperties: false
              description: The AI SDR the workflow picked (ub_ag_…); is_null:true = the workflows on their table's pick.
            q:
              type: string
              maxLength: 128
              description: Free text over name + description (MySQL LIKE, prefix/infix).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: '"Recently edited" scans; ISO 8601 range.'
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scopes the rows the metrics are computed over: the search filter operators. Omit for all rows."
        period:
          type: object
          properties:
            from:
              type: string
              description: ISO 8601 UTC window start (inclusive).
            to:
              type: string
              description: ISO 8601 UTC window end (exclusive); must be >= from.
          required:
            - from
            - to
          description: Required. Bounds the JOINED record clocks (enrollment / reply / completion), not workflows.created_at; filter scopes workflow rows.
        group_by:
          type: string
          enum:
            - status
          description: Single axis - adds groups[] with per-value counts + metrics. Cap 500 groups.
      required:
        - period
    GetWorkflowsMetricsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - metrics
        metrics:
          type: object
          properties:
            filter:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Echo of the request WorkflowSearchFilter (PHP empty map serialises as []).
            period:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: string
              required:
                - from
                - to
            aggregated:
              type: object
              properties:
                counts:
                  type: object
                  properties:
                    total_count:
                      type: integer
                      minimum: 0
                      description: Workflow rows matching the filter scope.
                    groups:
                      type: object
                      properties:
                        status:
                          anyOf:
                            - type: object
                              properties:
                                draft:
                                  type: integer
                                  minimum: 0
                                active:
                                  type: integer
                                  minimum: 0
                                paused:
                                  type: integer
                                  minimum: 0
                                archived:
                                  type: integer
                                  minimum: 0
                            - type: array
                              items: {}
                          description: Campaign distribution by status (feeds list badges); absent key = zero (PHP empty map serialises as []).
                      required:
                        - status
                  required:
                    - total_count
                    - groups
                metrics:
                  type: object
                  properties:
                    enrolled_in_period:
                      type: integer
                      minimum: 0
                      description: Records created within [period.from, period.to).
                    replied_in_period:
                      type: integer
                      minimum: 0
                      description: Records whose reply clock falls in the period.
                    completed_in_period:
                      type: integer
                      minimum: 0
                      description: Records that reached a terminal completed state in the period.
                    active_records_now:
                      type: integer
                      minimum: 0
                      description: Non-terminal records; point-in-time snapshot, period-independent.
                  required:
                    - enrolled_in_period
                    - replied_in_period
                    - completed_in_period
                    - active_records_now
              required:
                - counts
                - metrics
            groups:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: Value of the group_by axis (a WorkflowStatusEnum value).
                  counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Workflow rows matching the filter scope.
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                properties:
                                  draft:
                                    type: integer
                                    minimum: 0
                                  active:
                                    type: integer
                                    minimum: 0
                                  paused:
                                    type: integer
                                    minimum: 0
                                  archived:
                                    type: integer
                                    minimum: 0
                              - type: array
                                items: {}
                            description: Campaign distribution by status (feeds list badges); absent key = zero (PHP empty map serialises as []).
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                  metrics:
                    type: object
                    properties:
                      enrolled_in_period:
                        type: integer
                        minimum: 0
                        description: Records created within [period.from, period.to).
                      replied_in_period:
                        type: integer
                        minimum: 0
                        description: Records whose reply clock falls in the period.
                      completed_in_period:
                        type: integer
                        minimum: 0
                        description: Records that reached a terminal completed state in the period.
                      active_records_now:
                        type: integer
                        minimum: 0
                        description: Non-terminal records; point-in-time snapshot, period-independent.
                    required:
                      - enrolled_in_period
                      - replied_in_period
                      - completed_in_period
                      - active_records_now
                required:
                  - key
                  - counts
                  - metrics
              description: Present only when group_by was set - one entry per axis value. Cap 500 groups → 422.
          required:
            - period
            - aggregated
        applied_filters:
          type: object
          additionalProperties: {}
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - metrics
        - meta
    GetWorkspacePerformanceRequest:
      type: object
      description: Request body of `get_workspace_performance`.
      properties:
        days:
          type: integer
          minimum: 1
          maximum: 90
          description: "The window in the workspace's days, today included (the Dashboard shows 30 by default; its 24 hours is 1, today). Either this or from + to, never both. The series covers twice as many days: this window and the one before it, to compare against."
        from:
          type: string
          description: "A custom range instead of `days`: its first day, YYYY-MM-DD in the workspace's zone, with `to`."
        to:
          type: string
          description: The custom range's last day, YYYY-MM-DD, at or after `from` and at most 90 days after it.
        playtable_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^pt_tb_
            description: Playtable sid (pt_tb_…).
          maxItems: 200
          description: "Narrow to these tables: the people homed in them and the accounts of them (a member, or an account one of those people works at). Omit for every table; an unknown sid matches nobody."
        sender_profile_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_sp_
          maxItems: 200
          description: "Narrow to the people these sender profiles work: whose first touch (invite, message, InMail or email) went out from one of them, or with a workflow record pinned to one. Enrolled then dates by that record; the accounts kept are theirs."
    GetWorkspacePerformanceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            zone:
              type: string
              description: The workspace's IANA timezone; UTC when it has none.
            days:
              type: integer
            from:
              type: string
              description: "The window shown: its first day, YYYY-MM-DD in `zone`."
            to:
              type: string
              description: Its last day, both included.
            scope:
              type: object
              properties:
                playtable_sids:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                    description: Playtable sid (pt_tb_…).
                sender_profile_sids:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
              required:
                - playtable_sids
                - sender_profile_sids
              description: What the answer was narrowed to, as asked, each list once per sid; an empty list is no scope on that axis.
            steps:
              type: array
              items:
                type: string
                enum:
                  - added
                  - enrolled
                  - reached
                  - engaged
                  - replied
                  - positive
                  - meeting
                  - won
              description: The eight steps, in order.
            flow:
              type: object
              properties:
                people:
                  type: object
                  properties:
                    shown:
                      type: object
                      properties:
                        added:
                          type: integer
                          description: Rows created (people), or accounts created.
                        enrolled:
                          type: integer
                          description: First entered a workflow.
                        reached:
                          type: integer
                          description: "First touched: a connection request, a message, an InMail or an email went out."
                        engaged:
                          type: integer
                          description: First accepted our invite or replied.
                        replied:
                          type: integer
                          description: First replied at or after the first touch.
                        positive:
                          type: integer
                          description: First moved into a positive stage.
                        meeting:
                          type: integer
                          description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                        won:
                          type: integer
                          description: First moved into Closed-Won.
                      required:
                        - added
                        - enrolled
                        - reached
                        - engaged
                        - replied
                        - positive
                        - meeting
                        - won
                      description: "The window asked for: each person (or account) once per step, on the day they first got there."
                    before:
                      type: object
                      properties:
                        added:
                          type: integer
                          description: Rows created (people), or accounts created.
                        enrolled:
                          type: integer
                          description: First entered a workflow.
                        reached:
                          type: integer
                          description: "First touched: a connection request, a message, an InMail or an email went out."
                        engaged:
                          type: integer
                          description: First accepted our invite or replied.
                        replied:
                          type: integer
                          description: First replied at or after the first touch.
                        positive:
                          type: integer
                          description: First moved into a positive stage.
                        meeting:
                          type: integer
                          description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                        won:
                          type: integer
                          description: First moved into Closed-Won.
                      required:
                        - added
                        - enrolled
                        - reached
                        - engaged
                        - replied
                        - positive
                        - meeting
                        - won
                      description: "The same for the window before it: the base of a change."
                    now:
                      type: array
                      items:
                        type: object
                        properties:
                          key:
                            type: string
                            enum:
                              - added
                              - enrolled
                              - reached
                              - engaged
                              - replied
                              - positive
                              - meeting
                              - won
                          here:
                            type: integer
                            minimum: 0
                            description: Whose furthest step this is and who is still in progress there (not on an exit stage).
                          left:
                            type: integer
                            minimum: 0
                            description: Whose furthest step this is and who left from it to a nurture, negative or disqualified stage.
                        required:
                          - key
                          - here
                          - left
                      description: Where everyone stands today, one row per step in order.
                  required:
                    - shown
                    - before
                    - now
                accounts:
                  type: object
                  properties:
                    shown:
                      type: object
                      properties:
                        added:
                          type: integer
                          description: Rows created (people), or accounts created.
                        enrolled:
                          type: integer
                          description: First entered a workflow.
                        reached:
                          type: integer
                          description: "First touched: a connection request, a message, an InMail or an email went out."
                        engaged:
                          type: integer
                          description: First accepted our invite or replied.
                        replied:
                          type: integer
                          description: First replied at or after the first touch.
                        positive:
                          type: integer
                          description: First moved into a positive stage.
                        meeting:
                          type: integer
                          description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                        won:
                          type: integer
                          description: First moved into Closed-Won.
                      required:
                        - added
                        - enrolled
                        - reached
                        - engaged
                        - replied
                        - positive
                        - meeting
                        - won
                      description: "The window asked for: each person (or account) once per step, on the day they first got there."
                    before:
                      type: object
                      properties:
                        added:
                          type: integer
                          description: Rows created (people), or accounts created.
                        enrolled:
                          type: integer
                          description: First entered a workflow.
                        reached:
                          type: integer
                          description: "First touched: a connection request, a message, an InMail or an email went out."
                        engaged:
                          type: integer
                          description: First accepted our invite or replied.
                        replied:
                          type: integer
                          description: First replied at or after the first touch.
                        positive:
                          type: integer
                          description: First moved into a positive stage.
                        meeting:
                          type: integer
                          description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                        won:
                          type: integer
                          description: First moved into Closed-Won.
                      required:
                        - added
                        - enrolled
                        - reached
                        - engaged
                        - replied
                        - positive
                        - meeting
                        - won
                      description: "The same for the window before it: the base of a change."
                    now:
                      type: array
                      items:
                        type: object
                        properties:
                          key:
                            type: string
                            enum:
                              - added
                              - enrolled
                              - reached
                              - engaged
                              - replied
                              - positive
                              - meeting
                              - won
                          here:
                            type: integer
                            minimum: 0
                            description: Whose furthest step this is and who is still in progress there (not on an exit stage).
                          left:
                            type: integer
                            minimum: 0
                            description: Whose furthest step this is and who left from it to a nurture, negative or disqualified stage.
                        required:
                          - key
                          - here
                          - left
                      description: Where everyone stands today, one row per step in order.
                  required:
                    - shown
                    - before
                    - now
                  description: "Every account of the workspace: an account got as far as its furthest person, on the day the first of them did, and left when its own stage is an exit."
              required:
                - people
                - accounts
            series:
              type: array
              items:
                type: object
                properties:
                  added:
                    type: integer
                    description: Rows created (people), or accounts created.
                  enrolled:
                    type: integer
                    description: First entered a workflow.
                  reached:
                    type: integer
                    description: "First touched: a connection request, a message, an InMail or an email went out."
                  engaged:
                    type: integer
                    description: First accepted our invite or replied.
                  replied:
                    type: integer
                    description: First replied at or after the first touch.
                  positive:
                    type: integer
                    description: First moved into a positive stage.
                  meeting:
                    type: integer
                    description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                  won:
                    type: integer
                    description: First moved into Closed-Won.
                  date:
                    type: string
                    description: The workspace's calendar day, YYYY-MM-DD.
                required:
                  - added
                  - enrolled
                  - reached
                  - engaged
                  - replied
                  - positive
                  - meeting
                  - won
                  - date
              description: "People, 2 x days days, oldest first: the window before the shown one, then the shown one."
            added:
              type: object
              properties:
                by_source_type:
                  type: object
                  additionalProperties:
                    type: integer
                  description: The window's people by the kind of source that added them (ai_search, sender_search, find_people, csv, webhook; manual = by hand).
                sources_count:
                  type: integer
                  description: How many sources added someone in the window, by hand counted as one.
              required:
                - by_source_type
                - sources_count
            reached:
              type: object
              properties:
                by_channel:
                  type: object
                  properties:
                    linkedin:
                      type: integer
                      description: People whose first LinkedIn touch fell in the window.
                    email:
                      type: integer
                      description: People whose first email fell in the window; a person on both channels counts in each.
                  required:
                    - linkedin
                    - email
              required:
                - by_channel
            engaged:
              type: object
              properties:
                accepted:
                  type: integer
                  description: People who first accepted our invite in the window.
              required:
                - accepted
            tables:
              type: array
              items:
                type: object
                properties:
                  added:
                    type: integer
                    description: Rows created (people), or accounts created.
                  enrolled:
                    type: integer
                    description: First entered a workflow.
                  reached:
                    type: integer
                    description: "First touched: a connection request, a message, an InMail or an email went out."
                  engaged:
                    type: integer
                    description: First accepted our invite or replied.
                  replied:
                    type: integer
                    description: First replied at or after the first touch.
                  positive:
                    type: integer
                    description: First moved into a positive stage.
                  meeting:
                    type: integer
                    description: First moved into Meeting Requested, Meeting Scheduled or Closed-Won.
                  won:
                    type: integer
                    description: First moved into Closed-Won.
                  playtable_sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                    description: Playtable sid (pt_tb_…).
                  won_value:
                    type: number
                    description: The deal sizes of the accounts won through this table's people in the window.
                required:
                  - added
                  - enrolled
                  - reached
                  - engaged
                  - replied
                  - positive
                  - meeting
                  - won
                  - playtable_sid
                  - won_value
              description: The window's people counts per table, the most positive first.
            money:
              type: object
              properties:
                open_value:
                  type: number
                  description: Deal sizes of the accounts at Positive or Meeting, not won, not on an exit stage, today.
                open_accounts:
                  type: integer
                open_unpriced_accounts:
                  type: integer
                  description: Of the open accounts, the ones without a deal size.
                won_value:
                  type: number
                  description: Deal sizes of the accounts won in the window.
                won_accounts:
                  type: integer
                won_value_before:
                  type: number
                  description: The same for the window before.
                won_accounts_before:
                  type: integer
              required:
                - open_value
                - open_accounts
                - open_unpriced_accounts
                - won_value
                - won_accounts
                - won_value_before
                - won_accounts_before
            stages_by_day:
              type: array
              items:
                type: object
                properties:
                  date:
                    type: string
                  cold:
                    type: integer
                    description: "Everyone alive that day on no other category: a cold stage, or no stage."
                  approaching:
                    type: integer
                  engaging:
                    type: integer
                  positive:
                    type: integer
                  nurture:
                    type: integer
                  negative:
                    type: integer
                  disqualified:
                    type: integer
                required:
                  - date
                  - cold
                  - approaching
                  - engaging
                  - positive
                  - nurture
                  - negative
                  - disqualified
              description: "The people by stage category at the end of each day of the window, oldest first: today's stages walked back through the stage moves."
          required:
            - zone
            - days
            - from
            - to
            - scope
            - steps
            - flow
            - series
            - added
            - reached
            - engaged
            - tables
            - money
            - stages_by_day
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ImportDataSourceRequest:
      type: object
      description: Request body of `import_data_source`.
      properties:
        field_mapping:
          type: array
          items:
            type: object
            properties:
              source:
                type: string
                minLength: 1
                maxLength: 512
                description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
              target_kind:
                type: string
                enum:
                  - people_attribute
                  - company_attribute
                  - field_slug
                description: people_attribute | company_attribute | field_slug.
              target:
                type: string
                minLength: 1
                maxLength: 255
                description: Attribute key (people / company) or a playtable field slug in the target table.
              name:
                type: string
                nullable: true
                minLength: 1
                maxLength: 255
                description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
            required:
              - source
              - target_kind
              - target
          description: "May be []: a column preset, not a filter (mapping nothing stages every row whole). A field_slug target with no live column materializes one (named by name, else the CSV header); item.field_mapping is authoritative, a clashing slug rewritten."
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Override what the rows become: people | company. Absent = what the upload said."
        mode:
          type: string
          enum:
            - create
            - update
          description: "Override what the import does: create (new objects) | update (resolve an existing object by `match` and apply the mapped attributes). Absent = what the upload said."
        match:
          type: object
          properties:
            field:
              type: string
              enum:
                - person_sid
                - email
                - ln_nickname
                - company_sid
                - domain
                - name
              description: "Existing-row lookup key. people: person_sid | email (work or personal) | ln_nickname (a profile URL reduces to the slug). company: company_sid | ln_nickname | domain | name. Values are normalized the same way the stored identifiers are."
            csv_column:
              type: integer
              minimum: 0
              description: CSV column index carrying the match value (same indexing as field_mapping.source).
          required:
            - field
            - csv_column
          description: Required when the resulting mode is update, prohibited when it is create.
        on_duplicate:
          type: string
          enum:
            - skip
            - move
          description: Override before start; default = the draft's stored policy.
        add_tags_to_duplicate:
          type: boolean
          description: "Override before start: merge tag_sids onto matched duplicates; default = the draft's stored policy."
        qualify:
          type: object
          nullable: true
          properties:
            "on":
              type: boolean
              description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
            criterion:
              type: string
              nullable: true
              minLength: 1
              maxLength: 2000
              description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
          required:
            - "on"
            - criterion
          additionalProperties: false
          description: "The last word on the gate too: the block to run, null to switch it off, absent = what the upload said."
      required:
        - field_mapping
    ImportDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            total_rows:
              type: integer
              minimum: 0
              description: CSV data rows detected (header excluded).
            pending:
              type: object
              properties:
                expected_completion_seconds:
                  type: integer
                  minimum: 0
                  description: ~ceil(total_rows / 1000) * 60.
                webhook_events:
                  type: array
                  items:
                    anyOf:
                      - type: string
                        enum:
                          - data-sources.completed
                      - type: string
                        enum:
                          - data-sources.failed
                  minItems: 2
                  maxItems: 2
                  description: Terminal webhooks that close this parse.
                polling_hint:
                  type: string
                  description: e.g. "poll data_sources.get(sid, include=[data_source_items_counts]) until status is terminal".
              required:
                - expected_completion_seconds
                - webhook_events
                - polling_hint
              description: Inline async ref - no activity_log row exists in this service.
          required:
            - total_rows
            - pending
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ListPlayCatalogRequest:
      type: object
      description: Request body of `list_play_catalog`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: The table whose playbook is read.
      required:
        - playtable_sid
    ListPlayCatalogResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            items:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - keep_fresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
                      - find_people_empty
                      - top_up_thin
                      - top_up_silent
                      - top_up_no_reply
                      - top_up_exhausted
                      - find_decision_maker
                      - reengage_dormant
                      - reach_untouched
                    description: "The entry: the catalog_key a row born from it carries."
                  name:
                    type: string
                    description: The play's name as the tab shows it.
                  description:
                    type: string
                    description: "One line: whom it is for and what it does."
                  group:
                    type: string
                    enum:
                      - data
                      - moments
                      - social
                      - website
                      - accounts
                      - people
                    description: "The group the tab lists the entry under: data, moments, social, website, accounts, people."
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                    description: "company: the audience is accounts; people: the audience is people."
                  action_type:
                    type: string
                    enum:
                      - find_people
                      - add_to_workflow
                      - refresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
                    description: What a row born from it does.
                  signal_keys:
                    type: array
                    items:
                      type: string
                    description: "The signal name(s) the audience is: the chip the tab draws, the same name counts.groups.signals carries; empty for a play over the whole tab."
                  action:
                    anyOf:
                      - type: object
                        properties:
                          prompt:
                            type: string
                            nullable: true
                            description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                          per_company_limit:
                            type: integer
                            nullable: true
                            description: People taken per account, 1..25; null = the whole first page.
                          data_source_sid:
                            type: string
                            nullable: true
                            description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                        required:
                          - prompt
                          - per_company_limit
                          - data_source_sid
                      - type: object
                        properties:
                          workflow_sid:
                            type: string
                            nullable: true
                            description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                          workflow_source_sid:
                            type: string
                            nullable: true
                            description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                        required:
                          - workflow_sid
                          - workflow_source_sid
                      - type: object
                        properties:
                          moments:
                            type: object
                            properties:
                              birthday:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                              work_anniversary:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                              job_change:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                            description: A switch per moment with its own Do under it; a kind absent is off.
                        required:
                          - moments
                      - type: object
                        properties:
                          do:
                            type: string
                            enum:
                              - pause_and_ask
                              - remove_from_workflows
                              - move_to_workflow
                            description: For a person in a workflow whose title or company moved.
                          workflow_sid:
                            type: string
                            nullable: true
                            description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                        required:
                          - do
                          - workflow_sid
                      - type: object
                        properties:
                          like:
                            type: object
                            properties:
                              "on":
                                type: boolean
                              reaction:
                                type: string
                                enum:
                                  - ai
                                  - like
                                  - celebrate
                                  - support
                                  - love
                                  - insightful
                                  - funny
                                description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                            required:
                              - "on"
                              - reaction
                          comment:
                            type: object
                            properties:
                              "on":
                                type: boolean
                              brief:
                                type: string
                                nullable: true
                                maxLength: 2000
                                description: What the AI writes the comment from; required while on.
                            required:
                              - "on"
                              - brief
                          per_person_weekly_cap:
                            type: integer
                            minimum: 1
                            maximum: 14
                            description: At most this many acts a week per person.
                          sender_profile_sid:
                            type: string
                            nullable: true
                            description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                        required:
                          - like
                          - comment
                          - per_person_weekly_cap
                          - sender_profile_sid
                      - type: object
                        properties:
                          do:
                            type: string
                            enum:
                              - pause_and_ask
                              - add_to_workflow
                            description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                          workflow_sid:
                            type: string
                            nullable: true
                            description: "wf_wf_…: required when the Do is a workflow."
                          pages:
                            type: array
                            nullable: true
                            items:
                              type: string
                            description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                        required:
                          - do
                          - workflow_sid
                          - pages
                      - type: object
                        properties: {}
                        description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
                    description: "The entry's defaults: what a row born from it starts with (the prompt and the cap of a find_people play; a null workflow for a people play, picked on the row; the three templates of Congratulate; the Do of a job change)."
                  watch:
                    type: object
                    nullable: true
                    properties:
                      profile_days:
                        anyOf:
                          - type: number
                            enum:
                              - 7
                          - type: number
                            enum:
                              - 14
                          - type: number
                            enum:
                              - 30
                          - type: number
                            enum:
                              - 90
                          - {}
                        description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                      company_days:
                        anyOf:
                          - type: number
                            enum:
                              - 30
                          - type: number
                            enum:
                              - 90
                          - {}
                        description: "The company page every N days: 30 | 90; null = not watched."
                      posts_days:
                        anyOf:
                          - type: number
                            enum:
                              - 1
                          - type: number
                            enum:
                              - 3
                          - type: number
                            enum:
                              - 7
                          - {}
                        description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                      moments:
                        type: boolean
                        description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
                    required:
                      - profile_days
                      - company_days
                      - posts_days
                      - moments
                    description: What the entry watches (the born row's when there is one); null = nothing.
                  mode:
                    type: string
                    enum:
                      - ask_me
                      - automatic
                    description: "How the entry acts: ask me for the plays that act, automatic for the rest."
                  count:
                    type: integer
                    minimum: 0
                    description: "How many rows of the tab the audience matches now: the number to say when proposing the play."
                  credits_month:
                    type: number
                    nullable: true
                    description: What the watch costs a month over that audience (the born row's watch when there is one); null when nothing is watched on a cadence. The number to say before the switch.
                  play:
                    type: object
                    nullable: true
                    properties:
                      sid:
                        type: string
                        description: Play sid (pt_pl_…).
                      team_sid:
                        type: string
                        description: Owning team (ts_tm_…).
                      playtable_sid:
                        type: string
                        description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
                      catalog_key:
                        type: string
                        nullable: true
                        enum:
                          - keep_fresh
                          - congratulate
                          - on_job_change
                          - engage_posts
                          - on_website_visit
                          - find_people_empty
                          - top_up_thin
                          - top_up_silent
                          - top_up_no_reply
                          - top_up_exhausted
                          - find_decision_maker
                          - reengage_dormant
                          - reach_untouched
                        description: The playbook entry the row was born from; null = a play saved from a view's filter.
                      name:
                        type: string
                        description: The play's name, 1..255.
                      object_type:
                        type: string
                        enum:
                          - people
                          - company
                        description: "What the audience selects: people, or company (accounts)."
                      action_type:
                        type: string
                        enum:
                          - find_people
                          - add_to_workflow
                          - refresh
                          - congratulate
                          - on_job_change
                          - engage_posts
                          - on_website_visit
                        description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
                      action:
                        anyOf:
                          - type: object
                            properties:
                              prompt:
                                type: string
                                nullable: true
                                description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                              per_company_limit:
                                type: integer
                                nullable: true
                                description: People taken per account, 1..25; null = the whole first page.
                              data_source_sid:
                                type: string
                                nullable: true
                                description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                            required:
                              - prompt
                              - per_company_limit
                              - data_source_sid
                          - type: object
                            properties:
                              workflow_sid:
                                type: string
                                nullable: true
                                description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                              workflow_source_sid:
                                type: string
                                nullable: true
                                description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                            required:
                              - workflow_sid
                              - workflow_source_sid
                          - type: object
                            properties:
                              moments:
                                type: object
                                properties:
                                  birthday:
                                    type: object
                                    properties:
                                      "on":
                                        type: boolean
                                        description: The moment's switch.
                                      do:
                                        type: string
                                        enum:
                                          - send_message
                                          - add_to_workflow
                                        description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                      template:
                                        type: string
                                        nullable: true
                                        maxLength: 2000
                                        description: The message, in the workflow template grammar ({{people.first_name}}).
                                      workflow_sid:
                                        type: string
                                        nullable: true
                                        description: "wf_wf_…: the workflow, when the Do is a workflow."
                                    required:
                                      - "on"
                                      - do
                                      - template
                                      - workflow_sid
                                  work_anniversary:
                                    type: object
                                    properties:
                                      "on":
                                        type: boolean
                                        description: The moment's switch.
                                      do:
                                        type: string
                                        enum:
                                          - send_message
                                          - add_to_workflow
                                        description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                      template:
                                        type: string
                                        nullable: true
                                        maxLength: 2000
                                        description: The message, in the workflow template grammar ({{people.first_name}}).
                                      workflow_sid:
                                        type: string
                                        nullable: true
                                        description: "wf_wf_…: the workflow, when the Do is a workflow."
                                    required:
                                      - "on"
                                      - do
                                      - template
                                      - workflow_sid
                                  job_change:
                                    type: object
                                    properties:
                                      "on":
                                        type: boolean
                                        description: The moment's switch.
                                      do:
                                        type: string
                                        enum:
                                          - send_message
                                          - add_to_workflow
                                        description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                      template:
                                        type: string
                                        nullable: true
                                        maxLength: 2000
                                        description: The message, in the workflow template grammar ({{people.first_name}}).
                                      workflow_sid:
                                        type: string
                                        nullable: true
                                        description: "wf_wf_…: the workflow, when the Do is a workflow."
                                    required:
                                      - "on"
                                      - do
                                      - template
                                      - workflow_sid
                                description: A switch per moment with its own Do under it; a kind absent is off.
                            required:
                              - moments
                          - type: object
                            properties:
                              do:
                                type: string
                                enum:
                                  - pause_and_ask
                                  - remove_from_workflows
                                  - move_to_workflow
                                description: For a person in a workflow whose title or company moved.
                              workflow_sid:
                                type: string
                                nullable: true
                                description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                            required:
                              - do
                              - workflow_sid
                          - type: object
                            properties:
                              like:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                  reaction:
                                    type: string
                                    enum:
                                      - ai
                                      - like
                                      - celebrate
                                      - support
                                      - love
                                      - insightful
                                      - funny
                                    description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                                required:
                                  - "on"
                                  - reaction
                              comment:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                  brief:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: What the AI writes the comment from; required while on.
                                required:
                                  - "on"
                                  - brief
                              per_person_weekly_cap:
                                type: integer
                                minimum: 1
                                maximum: 14
                                description: At most this many acts a week per person.
                              sender_profile_sid:
                                type: string
                                nullable: true
                                description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                            required:
                              - like
                              - comment
                              - per_person_weekly_cap
                              - sender_profile_sid
                          - type: object
                            properties:
                              do:
                                type: string
                                enum:
                                  - pause_and_ask
                                  - add_to_workflow
                                description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                              workflow_sid:
                                type: string
                                nullable: true
                                description: "wf_wf_…: required when the Do is a workflow."
                              pages:
                                type: array
                                nullable: true
                                items:
                                  type: string
                                description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                            required:
                              - do
                              - workflow_sid
                              - pages
                          - type: object
                            properties: {}
                            description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
                        description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
                      audience:
                        description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
                      watch:
                        type: object
                        nullable: true
                        properties:
                          profile_days:
                            anyOf:
                              - type: number
                                enum:
                                  - 7
                              - type: number
                                enum:
                                  - 14
                              - type: number
                                enum:
                                  - 30
                              - type: number
                                enum:
                                  - 90
                              - {}
                            description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                          company_days:
                            anyOf:
                              - type: number
                                enum:
                                  - 30
                              - type: number
                                enum:
                                  - 90
                              - {}
                            description: "The company page every N days: 30 | 90; null = not watched."
                          posts_days:
                            anyOf:
                              - type: number
                                enum:
                                  - 1
                              - type: number
                                enum:
                                  - 3
                              - type: number
                                enum:
                                  - 7
                              - {}
                            description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                          moments:
                            type: boolean
                            description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
                        required:
                          - profile_days
                          - company_days
                          - posts_days
                          - moments
                        description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
                      cadence:
                        type: string
                        enum:
                          - manual
                          - daily
                        description: "manual: runs on run_play; daily: runs by itself every day while enabled."
                      mode:
                        type: string
                        enum:
                          - ask_me
                          - automatic
                        description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
                      enabled:
                        type: boolean
                        description: The switch of a daily play; a manual play is always false.
                      enabled_by:
                        type: object
                        nullable: true
                        properties:
                          actor_type:
                            type: string
                            enum:
                              - user
                              - support
                              - api_key
                              - system
                              - agent
                          actor_sid:
                            type: string
                            nullable: true
                          team_sid:
                            type: string
                          actor_name:
                            type: string
                            nullable: true
                            description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                          oauth_client_sid:
                            type: string
                            nullable: true
                            description: The acting OAuth client (id_oc_*); null off the OAuth path.
                          reason:
                            type: string
                            nullable: true
                            description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                          permissions:
                            type: object
                            additionalProperties: {}
                            description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                          cluster_id:
                            type: integer
                            nullable: true
                            description: "Internal audit context: the cluster that served the write."
                          trace_id:
                            type: string
                            nullable: true
                            description: "Internal audit context: the trace id of the request that wrote the row."
                        required:
                          - actor_type
                          - actor_sid
                          - team_sid
                          - permissions
                        description: Who gave the consent (switched the play on).
                      enabled_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when."
                      daily_credit_limit:
                        type: integer
                        nullable: true
                        description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
                      last_run_at:
                        type: string
                        nullable: true
                        description: ISO 8601 UTC.
                      last_run_counts:
                        type: object
                        nullable: true
                        properties:
                          matched:
                            type: integer
                            minimum: 0
                            description: Rows the audience matched at the run (the tab's count under the filter).
                          acted:
                            type: integer
                            minimum: 0
                            description: Accounts appended to the queue, or people entered or re-entered.
                          skipped:
                            type: integer
                            minimum: 0
                            description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                          credits:
                            type: integer
                            minimum: 0
                            description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
                        required:
                          - matched
                          - acted
                          - skipped
                          - credits
                        description: What the last run did; null before the first run.
                      next_run_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
                      created_by:
                        type: object
                        properties:
                          actor_type:
                            type: string
                            enum:
                              - user
                              - support
                              - api_key
                              - system
                              - agent
                          actor_sid:
                            type: string
                            nullable: true
                          team_sid:
                            type: string
                          actor_name:
                            type: string
                            nullable: true
                            description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                          oauth_client_sid:
                            type: string
                            nullable: true
                            description: The acting OAuth client (id_oc_*); null off the OAuth path.
                          reason:
                            type: string
                            nullable: true
                            description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                          permissions:
                            type: object
                            additionalProperties: {}
                            description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                          cluster_id:
                            type: integer
                            nullable: true
                            description: "Internal audit context: the cluster that served the write."
                          trace_id:
                            type: string
                            nullable: true
                            description: "Internal audit context: the trace id of the request that wrote the row."
                        required:
                          - actor_type
                          - actor_sid
                          - team_sid
                          - permissions
                      deleted_by:
                        type: object
                        nullable: true
                        properties:
                          actor_type:
                            type: string
                            enum:
                              - user
                              - support
                              - api_key
                              - system
                              - agent
                          actor_sid:
                            type: string
                            nullable: true
                          team_sid:
                            type: string
                          actor_name:
                            type: string
                            nullable: true
                            description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                          oauth_client_sid:
                            type: string
                            nullable: true
                            description: The acting OAuth client (id_oc_*); null off the OAuth path.
                          reason:
                            type: string
                            nullable: true
                            description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                          permissions:
                            type: object
                            additionalProperties: {}
                            description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                          cluster_id:
                            type: integer
                            nullable: true
                            description: "Internal audit context: the cluster that served the write."
                          trace_id:
                            type: string
                            nullable: true
                            description: "Internal audit context: the trace id of the request that wrote the row."
                        required:
                          - actor_type
                          - actor_sid
                          - team_sid
                          - permissions
                      created_at:
                        type: string
                        description: ISO 8601 UTC.
                      updated_at:
                        type: string
                        description: ISO 8601 UTC.
                      deleted_at:
                        type: string
                        nullable: true
                        description: ISO 8601 UTC; null = live.
                    required:
                      - sid
                      - team_sid
                      - playtable_sid
                      - catalog_key
                      - name
                      - object_type
                      - action_type
                      - action
                      - watch
                      - cadence
                      - mode
                      - enabled
                      - enabled_by
                      - enabled_at
                      - daily_credit_limit
                      - last_run_at
                      - last_run_counts
                      - next_run_at
                      - created_by
                      - deleted_by
                      - created_at
                      - updated_at
                      - deleted_at
                    description: The row born from this entry on the table (its switch, its last run, its workflow), or null until the first touch.
                required:
                  - key
                  - name
                  - description
                  - group
                  - object_type
                  - action_type
                  - signal_keys
                  - action
                  - watch
                  - mode
                  - count
                  - credits_month
                  - play
              description: "Every entry of the playbook, in the tab's order: Keep data fresh, the moments, Engage with posts, On a website visit, then the accounts from empty to closed, then the people."
          required:
            - items
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    MakeCompanyPrimaryResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        result:
          type: object
          properties:
            already_primary:
              type: boolean
              description: true = the row was not flagged; nothing changed.
            previous_primary_sid:
              type: string
              nullable: true
              description: The row that was the primary and is the duplicate now (cr_co_…); null when the row was simply lifted.
            repointed_count:
              type: integer
              description: Other copies of the old primary now pointing at this row.
          required:
            - already_primary
            - previous_primary_sid
            - repointed_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    MakePersonPrimaryResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              description: pt_tb_… - the SINGLE playtable membership; service-managed, changes only via move (create on_duplicate:move / run type move).
            data_source_sid:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            company_sid:
              type: string
              nullable: true
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                first_name:
                  type: string
                  nullable: true
                  description: The source's own first name when it gave one, else the first word of name.
                picture_url:
                  type: string
                  nullable: true
                  description: A permanent copy over a wire link, the wire link that lasts longest, an expired one counts as none.
                role:
                  type: string
                  nullable: true
                  description: The title at the company (the Sales Navigator wire's position, the enrichment's).
                headline:
                  type: string
                  nullable: true
                  description: The profile line (the regular and Recruiter wires, the inbox participant, the enrichment).
                company:
                  type: object
                  nullable: true
                  properties:
                    sid:
                      type: string
                      nullable: true
                      description: cr_co_… when the person is linked to an account (the account's own resolved context follows); null = a name that is not an account, an import whose company column resolved to none.
                    name:
                      type: string
                      nullable: true
                    domain:
                      type: string
                      nullable: true
                    picture_url:
                      type: string
                      nullable: true
                    ln_id:
                      type: string
                      nullable: true
                      description: "The company's LinkedIn id: the linked account's own, else the person's company id as a source or an edit gave it."
                  required:
                    - sid
                    - name
                    - domain
                    - picture_url
                    - ln_id
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - first_name
                - picture_url
                - role
                - headline
                - company
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, first name, picture, role, headline and company a surface or a model shows next to the row, resolved at read from the observations ledger: a manual word until reset, then the newest LinkedIn-derived observation, then any other. The only place these words are: the row keeps identifiers (phase E, 2026-10-22). Null only on an event payload."
            ln_member_id:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
            sn_id:
              type: string
              nullable: true
            recruiter_id:
              type: string
              nullable: true
            work_email:
              type: string
              nullable: true
            personal_email:
              type: string
              nullable: true
            work_phone_number:
              type: string
              nullable: true
            personal_phone_number:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - no_contact_data
                - duplicate
                - stoplisted
              description: Service-managed row validity (import validation, stoplist, duplicate detection) - not client-writable.
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY row (cr_pp_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_person_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_member_id
                - ln_id
                - sn_id
                - recruiter_id
                - email
                - ln_nickname
                - phone
              description: "While status is duplicate: the identifier the check matched on. Null otherwise."
            linkedin_status:
              type: string
              enum:
                - need_enrichment
                - enrichment_failed
                - no_data
                - blocked
                - ok
            email_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - bounced
                - ok
                - catch_all
                - unverified
            phone_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - ok
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: Free-form CRM sync map (hubspot_contact_id, …) - keys integration-defined, round-tripped as-is; PHP empty map serialises as [].
            last_enrich_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: The funnel stage the person is in (cr_ps_...), derived from activity or moved by hand (pipeline_stages.md); null = no stage.
          required:
            - sid
            - team_sid
            - playtable_sid
            - data_source_sid
            - data_source_item_sid
            - company_sid
            - context
            - ln_member_id
            - ln_id
            - sn_id
            - recruiter_id
            - work_email
            - personal_email
            - work_phone_number
            - personal_phone_number
            - status
            - duplicate_of_sid
            - duplicate_matched_kind
            - linkedin_status
            - email_status
            - phone_status
            - tag_sids
            - external_refs
            - last_enrich_at
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
        result:
          type: object
          properties:
            already_primary:
              type: boolean
              description: true = the row was not flagged; nothing changed.
            previous_primary_sid:
              type: string
              nullable: true
              description: The row that was the primary and is the duplicate now (cr_pp_…); null when the row was simply lifted.
            repointed_count:
              type: integer
              description: Other copies of the old primary now pointing at this row.
          required:
            - already_primary
            - previous_primary_sid
            - repointed_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    McpError:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - validation_failed
                - nothing_to_update
                - not_found
                - relation_not_found
                - invalid_transition
                - limit_exceeded
                - payment_required
                - duplicate_rejected
                - conflict
                - delete_blocked
                - unauthorized
                - forbidden
                - rate_limited
                - internal_error
                - service_unavailable
                - not_implemented
            message:
              type: string
            recoverable:
              type: boolean
            suggestion:
              type: string
            field_errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
            blockers:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: Machine-readable blocker type (active_flow, pending_tasks, …).
                  severity:
                    type: string
                    enum:
                      - hard
                      - soft
                    description: hard = external action required; soft = acknowledge is enough.
                  description:
                    type: string
                  entity_sid:
                    type: string
                    nullable: true
                  count:
                    type: integer
                  resolution:
                    type: string
                    description: "Hard: tool name to call. Soft: code for acknowledge[]."
                  resolution_hint:
                    type: string
                required:
                  - type
                  - severity
                  - description
                  - entity_sid
                  - resolution
                  - resolution_hint
            context:
              type: object
              additionalProperties: {}
          required:
            - code
            - message
            - recoverable
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - error
    MergeCompaniesRequest:
      type: object
      description: Request body of `merge_companies`.
      properties:
        into_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^cr_co_
          description: The TARGET (the primary account) that receives the leads and the membership.
      required:
        - into_sid
    MergeCompaniesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        result:
          type: object
          properties:
            source_sid:
              type: string
              description: The source that was drained (cr_co_…).
            moved_people_count:
              type: integer
              description: Leads repointed by THIS call; a re-run moves zero.
          required:
            - source_sid
            - moved_people_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    MoveDataSourceDuplicatesRequest:
      type: object
      description: Request body of `move_data_source_duplicates`.
      properties:
        data_source_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^ds_sc_
          description: The source whose duplicates move into its own table (ds_sc_…).
        sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ds_it_
            description: Item sid (ds_it_…).
          minItems: 1
          maxItems: 500
          description: The items to move (ds_it_…), a page of the review at most; absent = every duplicate the policy left in place.
      required:
        - data_source_sid
    MoveDataSourceDuplicatesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            moved:
              type: integer
              minimum: 0
              description: People moved into the table.
            left:
              type: integer
              minimum: 0
              description: "Rows that stayed: companies, and people whose row is gone."
            moved_sids:
              type: array
              items:
                type: string
              description: The items that now read moved.
          required:
            - moved
            - left
            - moved_sids
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    MovePipelineStageObjectsRequest:
      type: object
      description: Request body of `move_pipeline_stage_objects`.
      properties:
        object_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            description: A person (cr_pp_…) or company (cr_co_…) sid.
          minItems: 1
          maxItems: 1000
          description: "The objects to move, 1..1000 per call. Prefix must match the stage's object: cr_pp_ for a person stage, cr_co_ for a company stage. One mismatch rejects the whole call with 422 validation_failed."
      required:
        - object_sids
    MovePipelineStageObjectsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            moved_count:
              type: integer
              minimum: 0
              description: Objects whose stage actually changed (old != target).
            skipped_count:
              type: integer
              minimum: 0
              description: Objects already in the target stage - a no-op that writes no activity and no event.
          required:
            - moved_count
            - skipped_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PauseWorkflowRecordRequest:
      type: object
      description: Request body of `pause_workflow_record`.
      properties:
        reason:
          type: string
          maxLength: 512
          description: Free-form; stored in the workflow-records.paused event payload only - not on the row.
    PauseWorkflowRecordResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            workflow_sid:
              type: string
              description: wf_wf_… owning workflow; DB-UNIQUE together with people_sid - one row per (workflow, person) pair, forever - see ./workflows.md.
            workflow_version_sid:
              type: string
              description: wf_vr_… version pinned at enrollment - the record executes that step graph even after newer publishes - see ./workflow_versions.md.
            people_sid:
              type: string
              description: cr_pp_… the enrolled person; second half of the DB-UNIQUE pair - see ./people.md.
            entered_via_source_sid:
              type: string
              description: wf_sr_… entry point that produced the row (immutable audit) - see ./workflow_sources.md.
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… sender pinned at enrollment; null when the version has no send steps; re-resolved at next dispatch if the profile is deleted - see ./sender_profiles.md.
            current_step_id:
              type: number
              description: Small int step id inside the pinned version steps JSON (server-assigned, immutable, never reused) - a JSON node pointer, not a sid or row.
            status:
              type: string
              enum:
                - waiting_limit
                - blocked
                - active
                - waiting
                - paused_on_reply
                - paused_manual
                - paused_blocked
                - failed
                - completed
                - exited
            entered_at:
              type: string
              nullable: true
            touches_done:
              type: integer
              minimum: 0
            rotations_done:
              type: integer
              minimum: 0
            error_code:
              type: string
              nullable: true
              description: Machine code of the last failure, from the failing task result (max 64).
            error_message:
              type: string
              nullable: true
              description: Human-readable detail of the last failure (max 1024).
            last_touch_at:
              type: string
              description: ISO 8601 UTC - last step advance or status change; the staleness clock.
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once when status enters a terminal state; null while live.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - people_sid
            - entered_via_source_sid
            - sender_profile_sid
            - current_step_id
            - status
            - entered_at
            - touches_done
            - rotations_done
            - error_code
            - error_message
            - last_touch_at
            - finished_at
            - created_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_paused:
              type: boolean
              description: true = idempotent no-op (the record was already paused_manual).
          required:
            - already_paused
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PauseWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            records_active_count:
              type: integer
              minimum: 0
              description: Non-terminal records now frozen in place.
            tasks_scheduled_count:
              type: integer
              minimum: 0
              description: Scheduled tasks now held at the dispatch gate.
          required:
            - records_active_count
            - tasks_scheduled_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PlanDataSourceFiltersRequest:
      type: object
      description: Request body of `plan_data_source_filters`.
      properties:
        prompt:
          type: string
          minLength: 3
          maxLength: 2000
          description: Who to find, in the user's words ("CMOs at fintech companies in DACH", "heads of growth").
        vertical:
          type: string
          enum:
            - people
            - company
          description: people (default) | company - what the search brings back.
        company_scoped:
          type: boolean
          description: "Default false. true = a find_people plan: who to find inside companies selected in a grid; current companies are left out of the filter, the selection supplies them."
      required:
        - prompt
    PlanDataSourceFiltersResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            engine:
              type: string
              description: 'Always "sales_nav": the wire engine the filters are written for; the collector runs them only under it.'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "The kind to create with this plan: ai_search for an open search, find_people for a company_scoped one."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What the plan finds (the vertical): people | company. Pass it to create_data_source."
            filters:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: "The wire-ready filter set: pass it verbatim as payload.filters. Different facets are ANDed and the values inside one facet ORed. Id facets ride as [{id}] (locations, industries, current_companies, past_companies, schools), the fixed lists as flat ids (seniority_levels, functions, company_headcounts), titles as [{text}] (current_titles)."
            chips:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: "The semantic key the term fills: titles, seniorities, functions, company_sizes, locations, industries, current_companies, past_companies, schools, keywords, network, company_types."
                  term:
                    type: string
                    description: The human term as the description put it.
                  id:
                    type: string
                    description: The facet id it resolved to; absent on a free-text facet (a title rides as text).
                  label:
                    type: string
                    description: The label the search resolved for that id.
                required:
                  - key
                  - term
              description: The human reading of the same filter, one chip per term (what the product shows under "View details"). Relay these to the user before you create anything.
            unresolved:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                  term:
                    type: string
                required:
                  - key
                  - term
              description: "Terms no facet id was found for: DROPPED from filters, never faked. Resolve one with suggest_data_source_filter_values and add the chosen id under the matching wire key, or tell the user the search is narrower than asked."
            warnings:
              type: array
              items:
                type: string
              description: Sentences worth relaying to the user.
            suggested_name:
              type: string
              description: "A source name derived from the description (max 255): pass it as name."
          required:
            - engine
            - type
            - object_type
            - filters
            - chips
            - unresolved
            - warnings
            - suggested_name
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PreviewPlaytableDeleteResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            company_default_view_sid:
              type: string
              description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
            people_default_view_sid:
              type: string
              description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
              required:
                - auto_run
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - agent_sid
            - company_default_view_sid
            - people_default_view_sid
            - config
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_deleted:
              type: boolean
              description: "true when the table is gone already: then blockers and cascade are empty."
            blockers:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: Machine-readable blocker type (active_flow, pending_tasks, …).
                  severity:
                    type: string
                    description: hard = resolve it with another tool first (the delete refuses until it is gone); soft = pass its resolution code in delete_playtable's acknowledge[].
                  description:
                    type: string
                  entity_sid:
                    type: string
                    nullable: true
                  count:
                    type: integer
                  resolution:
                    type: string
                    description: "Hard: tool name to call. Soft: code for acknowledge[]."
                  resolution_hint:
                    type: string
                required:
                  - type
                  - severity
                  - description
                  - resolution
                  - resolution_hint
              description: Hard first (resolve them with other tools), then every soft one, none waived; delete_playtable takes the soft ones' resolution codes as acknowledge[].
            cascade:
              type: object
              properties:
                details:
                  type: array
                  items:
                    type: object
                    properties:
                      entity:
                        type: string
                      deleted:
                        type: integer
                        minimum: 0
                    required:
                      - entity
                      - deleted
                  description: "Per-entity projected counts: people, playtable_views, playtable_fields, playtable_field_deps, playtable_field_values (with queued, the cells cancelled unspent), data_sources (deleted 0, with paused: sources are paused and detached, never deleted)."
                retained:
                  type: array
                  items:
                    type: object
                    properties:
                      entity:
                        type: string
                      kept:
                        type: integer
                        minimum: 0
                    required:
                      - entity
                      - kept
                  description: "What survives: companies (multi-table membership), with how many keep their other tables."
              required:
                - details
                - retained
          required:
            - already_deleted
            - blockers
            - cascade
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PreviewPlaytableFieldConditionRequest:
      type: object
      description: Request body of `preview_playtable_field_condition`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_type:
          type: string
          enum:
            - people
            - company
          description: "Which rows the gate is about, people or company: the tab the draft column belongs to."
        run_condition:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                    is_null:
                      type: boolean
                    contains:
                      type: string
                      minLength: 1
                    not_contains:
                      type: string
                      minLength: 1
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                    starts_with:
                      type: string
                      minLength: 1
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
            - {}
          description: The unsaved gate, the shape config.run_condition takes; null or absent = no gate, every row runs. An unknown record.<slug> or a bad atom is 422 here, not at save.
        object_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
          minItems: 1
          maxItems: 100
          description: 1..100 distinct row sids of the tab (cr_pp_… or cr_co_…) to try the gate on.
      required:
        - playtable_sid
        - object_type
        - object_sids
    PreviewPlaytableFieldConditionResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            rows:
              type: array
              items:
                type: object
                properties:
                  object_sid:
                    type: string
                  will_run:
                    type: boolean
                required:
                  - object_sid
                  - will_run
              description: One verdict per named row, in the order given.
            will_run_count:
              type: integer
              minimum: 0
            evaluated_count:
              type: integer
              minimum: 0
          required:
            - rows
            - will_run_count
            - evaluated_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PreviewPlaytableFieldRunRequest:
      type: object
      description: Request body of `preview_playtable_field_run`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Owner playtable sid (pt_tb_…).
        object_sid:
          type: string
          minLength: 18
          maxLength: 18
          description: The one row to try the draft on (cr_pp_… or cr_co_…), of this table and this team.
        type:
          type: string
          enum:
            - action_ai_research
          description: "What the draft column is. Only action_ai_research runs inline today: waterfall and tool columns run through the queued executor and have no preview."
        payload:
          type: object
          properties:
            prompt:
              type: string
              minLength: 1
              maxLength: 8192
              description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
            model:
              type: string
              minLength: 1
              maxLength: 128
              description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
            output:
              type: string
              enum:
                - text
                - number
                - select
                - json
              description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
            options:
              type: array
              nullable: true
              items:
                type: string
              minItems: 1
              description: Required (min 1) when output=select; null otherwise.
            output_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  path:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 128
                    description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                required:
                  - path
                  - target
              maxItems: 20
              description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
            web_search:
              type: boolean
              description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
          required:
            - prompt
            - model
            - output
            - options
            - output_mapping
          description: "The drawer's live draft (prompt, model, output, options, output_mapping, web_search), validated exactly like create_playtable_field's: a payload that previews is a payload that saves."
        run_condition:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                    is_null:
                      type: boolean
                    contains:
                      type: string
                      minLength: 1
                    not_contains:
                      type: string
                      minLength: 1
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                    starts_with:
                      type: string
                      minLength: 1
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
            - {}
          description: The draft gate; a row it skips costs nothing and answers will_run false. null or absent = no gate.
      required:
        - playtable_sid
        - object_sid
        - type
        - payload
    PreviewPlaytableFieldRunResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            object_sid:
              type: string
            will_run:
              type: boolean
              description: "false = the gate or the empty-context rule skipped the row: no call, no charge, skip_reason says which."
            skip_reason:
              type: string
              nullable: true
              description: run_condition_not_met (the gate) or empty_context (every row reference of the prompt resolved to nothing); null when the row ran.
            value:
              type: string
              nullable: true
              description: What the cell would hold; null when the row was skipped, the call failed or the answer could not be coerced to payload.output.
            error_code:
              type: string
              nullable: true
              description: model_not_in_catalog or web_search_not_supported (refused before any charge), a lane code (the call failed), or the coercion failure of an answer the model gave and the team paid for; null on success.
            error_message:
              type: string
              nullable: true
            reasoning:
              type: string
              nullable: true
              description: The model's reasoning when it gave one.
            confidence:
              type: string
              nullable: true
            model:
              type: string
              nullable: true
              description: The model that answered (the resolved one when payload.model is auto); null when nothing was called.
            credits_charged:
              type: number
              minimum: 0
              description: The platform's own charge for this one row, in credits; 0 on a skip or a refusal before the call.
            duration_ms:
              type: integer
              minimum: 0
          required:
            - object_sid
            - will_run
            - skip_reason
            - value
            - error_code
            - error_message
            - reasoning
            - confidence
            - model
            - credits_charged
            - duration_ms
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PreviewPostEngagementRequest:
      type: object
      description: Request body of `preview_post_engagement`.
      properties:
        url:
          type: string
          maxLength: 2048
          format: uri
          description: A post link (/posts/…, /feed/update/…, a lnkd.in shortlink), a profile link (/in/{slug}) or a company page link (/company/{slug}); any other link is 422 link_not_recognized.
        sender_profile_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: "The sender profile whose LinkedIn account reads the link (ub_sp_), the one the source will run on; one that cannot read LinkedIn now is 422 with gtm's reason. A busy seat is 409 preview_unavailable (context.retry_after_seconds): create still works."
      required:
        - url
        - sender_profile_sid
    PreviewPostEngagementResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            target:
              type: string
              enum:
                - post
                - person
                - company
              description: "What the link is: post | person | company. Pass it as payload.target to create_data_source, or leave it to the link."
            post:
              type: object
              nullable: true
              properties:
                urn:
                  type: string
                author:
                  type: object
                  properties:
                    name:
                      type: string
                    ln_nickname:
                      type: string
                    headline:
                      type: string
                    picture_url:
                      type: string
                text:
                  type: string
                  description: The post's text, cut to 600 characters.
                published_at:
                  type: string
                  nullable: true
                counts:
                  type: object
                  properties:
                    reactions:
                      type: integer
                      minimum: 0
                    comments:
                      type: integer
                      minimum: 0
                    reposts:
                      type: integer
                      minimum: 0
                  required:
                    - reactions
                    - comments
                    - reposts
                  description: What each collect switch would read.
              required:
                - urn
                - author
                - text
                - published_at
                - counts
              description: "target=post: the post's card; null when it could not be read (deleted, private): the source would fail post_unavailable, so do not create it."
            person:
              type: object
              properties:
                name:
                  type: string
                ln_nickname:
                  type: string
                headline:
                  type: string
                picture_url:
                  type: string
              required:
                - ln_nickname
              description: "target=person: who the profile link is, from their feed (the lite profile names a person with no posts)."
            company:
              type: object
              properties:
                ln_nickname:
                  type: string
                ln_id:
                  type: string
                name:
                  type: string
                logo_url:
                  type: string
                headline:
                  type: string
              required:
                - ln_nickname
              description: "target=company: the page behind the link, by slug and numeric id; headline is the line LinkedIn shows under the page's name on its own posts (its followers), when a post was read."
            posts:
              type: array
              items:
                type: object
                properties:
                  urn:
                    type: string
                    description: urn:li:activity:… - the post the walk would address.
                  published_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null when the feed gave no date.
                  title:
                    type: string
                    description: The first line of the post, cut to 120 characters.
                  counts:
                    type: object
                    properties:
                      reactions:
                        type: integer
                        minimum: 0
                      comments:
                        type: integer
                        minimum: 0
                      reposts:
                        type: integer
                        minimum: 0
                    required:
                      - reactions
                      - comments
                      - reposts
                    description: "The post's three counts: sum them over the posts in the window for what each collect switch would read."
                required:
                  - urn
                  - published_at
                  - title
              description: "target=person | company: up to 20 recent posts with their dates and counts, so a caller can count how many fall in a window, and how much engagement, before creating the source."
          required:
            - target
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    PublishWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            version:
              type: object
              properties:
                sid:
                  type: string
                  description: wf_vr_….
                workflow_sid:
                  type: string
                  description: wf_wf_… parent.
                version:
                  type: integer
                  description: Per-workflow sequence, >=1 (max+1 at publish).
                steps:
                  type: array
                  items:
                    oneOf:
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_connection_request
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          message:
                            type: string
                            nullable: true
                            description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_message
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          message:
                            type: string
                            minLength: 1
                            maxLength: 8000
                            description: Message template (same namespaces as all templates).
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - message
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_send_inmail
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          subject:
                            type: string
                            nullable: true
                            maxLength: 200
                          message:
                            type: string
                            minLength: 1
                            maxLength: 8000
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - message
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_visit_profile
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_endorse_skills
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          skills_count:
                            type: integer
                            minimum: 1
                            maximum: 10
                            description: Endorse the person's top N listed skills, 1..10.
                        required:
                          - type
                          - skills_count
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_withdraw_connection_request
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_like_latest_post
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - linkedin_comment_latest_post
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          comment:
                            type: string
                            minLength: 1
                            maxLength: 1250
                            description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                        required:
                          - type
                          - comment
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - email_send
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          subject:
                            type: string
                            minLength: 1
                            maxLength: 255
                          body:
                            type: string
                            minLength: 1
                            maxLength: 100000
                            description: HTML body template.
                          required_fields:
                            type: object
                            nullable: true
                            properties:
                              refs:
                                type: array
                                items:
                                  type: string
                                  maxLength: 160
                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                maxItems: 20
                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                              on_missing:
                                type: string
                                enum:
                                  - fail
                                  - skip
                                description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                            required:
                              - refs
                              - on_missing
                            additionalProperties: false
                          email_field:
                            type: string
                            nullable: true
                            description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                          cc:
                            type: array
                            nullable: true
                            items:
                              type: string
                              maxLength: 320
                              format: email
                            maxItems: 5
                            description: Up to 5 literal copy addresses.
                          bcc:
                            type: array
                            nullable: true
                            items:
                              type: string
                              maxLength: 320
                              format: email
                            maxItems: 5
                            description: Up to 5 literal blind-copy addresses.
                          attachments:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                sid:
                                  type: string
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^wf_at_
                                name:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                              required:
                                - sid
                                - name
                              additionalProperties: false
                            maxItems: 5
                            description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                          reply_in_thread:
                            type: boolean
                            nullable: true
                          track_opens:
                            type: boolean
                            nullable: true
                          track_clicks:
                            type: boolean
                            nullable: true
                          unsubscribe_link:
                            type: boolean
                            nullable: true
                        required:
                          - type
                          - subject
                          - body
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - wait
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          for:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                        required:
                          - type
                          - for
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - wait_for_event
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          event:
                            type: string
                            enum:
                              - linkedin_connection_request_accepted
                              - email_opened
                              - email_link_clicked
                            description: Event observed via the activities ingest.
                          timeout:
                            type: object
                            properties:
                              after:
                                type: string
                                pattern: ^[1-9][0-9]*[mhd]$
                                description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                              steps:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - after
                              - steps
                            additionalProperties: false
                            description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                        required:
                          - type
                          - event
                          - timeout
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - condition
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                                label:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor caption.
                                when:
                                  type: object
                                  additionalProperties: {}
                                  description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                                steps:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - when
                                - steps
                              additionalProperties: false
                            minItems: 1
                            maxItems: 9
                            description: 1..9 branches, evaluated in order, first match wins.
                          else:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - type
                          - branches
                          - else
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - ab_test
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                                label:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor caption ("Variant A").
                                weight:
                                  type: integer
                                  minimum: 1
                                  description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                                steps:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - weight
                                - steps
                              additionalProperties: false
                            minItems: 2
                            maxItems: 9
                            description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                        required:
                          - type
                          - branches
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - end
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                        required:
                          - type
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - api_call
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          method:
                            type: string
                            enum:
                              - GET
                              - POST
                              - PUT
                              - PATCH
                              - DELETE
                          url:
                            type: string
                            minLength: 1
                            maxLength: 2048
                            description: https-only (publish check); a template - variables may stand in the path and the query.
                          headers:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: string
                              maxLength: 1024
                          query:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: string
                              maxLength: 2048
                          body:
                            type: string
                            nullable: true
                            maxLength: 16000
                            description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                          provider_connection_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^in_cn_
                            description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                          timeout_secs:
                            type: integer
                            nullable: true
                            minimum: 1
                            maximum: 120
                          retry_on_error:
                            type: boolean
                            nullable: true
                          remove_empty_values:
                            type: boolean
                            nullable: true
                          output_key:
                            type: string
                            nullable: true
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                        required:
                          - type
                          - method
                          - url
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - ask_ai
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          prompt:
                            type: string
                            minLength: 1
                            maxLength: 8000
                            description: Same variable namespaces as message templates.
                          output_key:
                            type: string
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                          preset_sid:
                            type: string
                            nullable: true
                            description: gtm-api preset for the AI call; null = team default.
                        required:
                          - type
                          - prompt
                          - output_key
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - manual_task
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          title:
                            type: string
                            minLength: 1
                            maxLength: 255
                          instructions:
                            type: string
                            nullable: true
                            maxLength: 4000
                            description: Rendered into the human todo; the journey waits until the task is completed.
                        required:
                          - type
                          - title
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - move_to_workflow
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          target_workflow_sid:
                            type: string
                            minLength: 18
                            maxLength: 18
                            pattern: ^wf_wf_
                            description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                          mode:
                            type: string
                            nullable: true
                            enum:
                              - from_start
                              - from_current
                            description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                        required:
                          - type
                          - target_workflow_sid
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - add_tag
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          tag_sids:
                            type: array
                            items:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^cr_tg_
                            minItems: 1
                            maxItems: 20
                            description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                        required:
                          - type
                          - tag_sids
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - remove_tag
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          tag_sids:
                            type: array
                            items:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^cr_tg_
                            minItems: 1
                            maxItems: 20
                            description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                        required:
                          - type
                          - tag_sids
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - set_field
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          field_slug:
                            type: string
                            pattern: ^[a-z][a-z0-9_]{0,63}$
                            description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                          value:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                              - {}
                              - {}
                            description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                        required:
                          - type
                          - field_slug
                          - value
                        additionalProperties: false
                      - type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - change_sender
                          id:
                            type: integer
                            minimum: 1
                            description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                          name:
                            type: string
                            nullable: true
                            maxLength: 255
                            description: Editor label.
                          sender_profile_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^ub_sp_
                            description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                          rotation:
                            type: string
                            nullable: true
                            enum:
                              - fair
                              - random
                              - new_sender
                              - prior_engagement
                            description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                        required:
                          - type
                        additionalProperties: false
                  description: Immutable snapshot of the step document at publish.
                steps_count:
                  type: integer
                  description: Denormalized total step count (incl. nested).
                entry_step_id:
                  type: integer
                  description: = steps[0].id - enrollment starts here.
                created_at:
                  type: string
                  description: ISO 8601 UTC - publish moment.
              required:
                - sid
                - workflow_sid
                - version
                - steps
                - steps_count
                - entry_step_id
                - created_at
              description: The immutable workflow_versions row this publish created, or the live one when unchanged - see ./workflow_versions.md.
            previous_version_sid:
              type: string
              nullable: true
              description: published_version_sid before this publish; null on first publish; the live version's own sid when unchanged.
            unchanged:
              type: boolean
              description: "true = the saved draft was already the published version: nothing was minted, no event, version is the live one."
          required:
            - version
            - previous_version_sid
            - unchanged
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ReadLinkedinCompanyRequest:
      type: object
      description: Request body of `read_linkedin_company`.
      properties:
        ln_nickname:
          type: string
          nullable: true
          minLength: 1
          maxLength: 2048
          description: The company page slug, or its linkedin.com/company/ link; parsed at the edge, never stored. One of ln_nickname, ln_id and domain.
        ln_id:
          type: string
          nullable: true
          pattern: ^\d{1,20}$
          description: "The page's numeric LinkedIn id, as digits (read_linkedin_person's company_ln_id), when the slug is not known: the page is read by the address LinkedIn serves for it."
        domain:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: "The company's website domain (acme.com, a URL accepted), when neither the slug nor the id is known: a corpus lookup, which answers only a page the corpus already knows (found false, reason company_not_resolvable, otherwise)."
    ReadLinkedinCompanyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            found:
              type: boolean
              description: LinkedIn served the page.
            comped:
              type: boolean
              description: The read ran on the onboarding allowance at price 0 (the first three pool reads of a team).
            company:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                tagline:
                  type: string
                  nullable: true
                about:
                  type: string
                  nullable: true
                  description: The page's about text.
                industry:
                  type: string
                  nullable: true
                people_count:
                  type: integer
                  nullable: true
                  description: The page's headcount; null when the read served a size bucket only.
                founded_year:
                  type: integer
                  nullable: true
                location:
                  type: string
                  nullable: true
                  description: The headquarters as "City, Area, Country".
                website:
                  type: string
                  nullable: true
                ln_id:
                  type: string
                  nullable: true
                  description: The numeric company id, as digits.
                ln_nickname:
                  type: string
                  nullable: true
                  description: The page slug, never a URL.
              required:
                - name
                - tagline
                - about
                - industry
                - people_count
                - founded_year
                - location
                - website
                - ln_id
                - ln_nickname
              description: The page's words and axes when found.
            reason:
              type: string
              description: "Why found is false: company_not_resolvable (the domain maps to no page), company_not_found (no page at the slug), company_unreadable (LinkedIn would not serve it) or pool_unavailable (no capacity: retry_after)."
            retry_after:
              anyOf:
                - type: string
                - type: number
                - {}
              description: "With pool_unavailable: when to ask again."
          required:
            - found
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ReadLinkedinPersonRequest:
      type: object
      description: Request body of `read_linkedin_person`.
      properties:
        ln_nickname:
          type: string
          minLength: 1
          maxLength: 2048
          description: The profile slug (public identifier), or the linkedin.com/in/ link as the person pasted it; parsed at the edge, never stored.
      required:
        - ln_nickname
    ReadLinkedinPersonResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            alive:
              type: boolean
              description: LinkedIn served the profile.
            comped:
              type: boolean
              description: The read ran on the onboarding allowance at price 0 (the first three pool reads of a team).
            person:
              type: object
              nullable: true
              properties:
                full_name:
                  type: string
                  nullable: true
                headline:
                  type: string
                  nullable: true
                role_title:
                  type: string
                  nullable: true
                  description: The current position's title.
                company_name:
                  type: string
                  nullable: true
                  description: The current company's name.
                company_ln_nickname:
                  type: string
                  nullable: true
                  description: "The current company's page slug: what read_linkedin_company takes."
                company_ln_id:
                  type: string
                  nullable: true
                  description: "The current company's numeric LinkedIn id, as digits: what read_linkedin_company takes as ln_id when the slug is unknown."
                location:
                  type: string
                  nullable: true
                avatar_url:
                  type: string
                  nullable: true
                  description: The photo, as an https address on our own store (never a LinkedIn address); null when the page shows none. update_user_profile takes it as avatar_url.
                positions:
                  type: array
                  items:
                    type: object
                    properties:
                      title:
                        type: string
                        nullable: true
                      company:
                        type: string
                        nullable: true
                      company_ln_nickname:
                        type: string
                        nullable: true
                        description: "This position's company page slug, when the profile names it: what read_linkedin_company takes when the person runs two companies and picks this one."
                      company_ln_id:
                        type: string
                        nullable: true
                        description: "This position's company id, as digits, when the profile names it: read_linkedin_company's ln_id when the slug is unknown."
                      from:
                        type: string
                        nullable: true
                        description: As LinkedIn wrote it ("Mar 2021").
                      to:
                        type: string
                        nullable: true
                        description: "Null on the position still running: two or more such positions under different companies is the person running two companies, and which one the workspace is for is theirs to say."
                    required:
                      - title
                      - company
                      - company_ln_nickname
                      - company_ln_id
                      - from
                      - to
                  description: The experience, newest first.
                languages:
                  type: array
                  items:
                    type: string
                  description: The Languages card when the profile carries one; empty otherwise.
                ln_member_id:
                  type: integer
                  nullable: true
                ln_id:
                  type: string
                  nullable: true
                  description: The profile URN.
                ln_nickname:
                  type: string
                  nullable: true
                  description: The public identifier (slug), never a URL.
              required:
                - full_name
                - headline
                - role_title
                - company_name
                - company_ln_nickname
                - company_ln_id
                - location
                - avatar_url
                - positions
                - languages
                - ln_member_id
                - ln_id
                - ln_nickname
              description: The profile's words and axes when alive.
            reason:
              type: string
              description: "Why alive is false: profile_not_found (no profile at the identifier), profile_unreadable (LinkedIn would not serve it) or pool_unavailable (no capacity: ask again after retry_after)."
            retry_after:
              anyOf:
                - type: string
                - type: number
                - {}
              description: "With pool_unavailable: when to ask again."
          required:
            - alive
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ReadSenderProfileStatsRequest:
      type: object
      description: Request body of `read_sender_profile_stats`.
      properties:
        sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_sp_
            description: "Sender profile sid (ub_sp_…): the unibox sid, the same on the playtables copy."
          minItems: 1
          maxItems: 200
          description: The sender profiles to read (ub_sp_…), 1 to 200. The answer holds one row per sid that names a sender profile of the team, in no fixed order; a sid no row answers to is left out, never an error.
        from:
          type: string
          description: "The period's start: an ISO 8601 date or moment (a date reads as its midnight UTC). The ledger's done sends and profile visits from here on count under `period`; the day blocks, the week and the last action do not depend on it."
        to:
          type: string
          description: "The period's end: after `from`, at most 367 days after it (the last 12 months fit in any zone). Exclusive."
      required:
        - sids
        - from
        - to
    ReadSenderProfileStatsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            sender_profiles:
              type: array
              items:
                type: object
                properties:
                  sid:
                    type: string
                    description: The sender profile the row answers for (ub_sp_…), one of the sids asked.
                  linkedin:
                    type: object
                    nullable: true
                    properties:
                      synced_at:
                        type: string
                        nullable: true
                        description: When the pacing mirror last read gtm's counters (ISO 8601 UTC, the latest of the four kinds); null when never synced.
                      invites:
                        type: object
                        properties:
                          done:
                            type: integer
                            minimum: 0
                            description: "Done today of this kind, in gtm's day: everything the account did, whoever asked for it."
                          limit:
                            type: integer
                            nullable: true
                            description: Today's cap of this kind (gtm's smart limit); null when the pacing mirror holds none.
                          hold:
                            type: boolean
                            description: "Whether this kind is held right now: the dispatcher sends none of it until hold_until."
                          hold_until:
                            type: string
                            nullable: true
                            description: "ISO 8601 UTC: when the hold lifts; null while not held."
                          hold_reason:
                            type: string
                            nullable: true
                            description: "Why it is held: daily_limit_reached (the cap is spent, or gtm reported the day saturated; lifts at gtm's next day), linkedin_limit_hit (LinkedIn itself refused the action: the account is off that kind until the hold lifts) or limit_hold (a hold of another cause); null while not held."
                        required:
                          - done
                          - limit
                          - hold
                          - hold_until
                          - hold_reason
                        description: Connection requests.
                      messages:
                        type: object
                        properties:
                          done:
                            type: integer
                            minimum: 0
                            description: "Done today of this kind, in gtm's day: everything the account did, whoever asked for it."
                          limit:
                            type: integer
                            nullable: true
                            description: Today's cap of this kind (gtm's smart limit); null when the pacing mirror holds none.
                          hold:
                            type: boolean
                            description: "Whether this kind is held right now: the dispatcher sends none of it until hold_until."
                          hold_until:
                            type: string
                            nullable: true
                            description: "ISO 8601 UTC: when the hold lifts; null while not held."
                          hold_reason:
                            type: string
                            nullable: true
                            description: "Why it is held: daily_limit_reached (the cap is spent, or gtm reported the day saturated; lifts at gtm's next day), linkedin_limit_hit (LinkedIn itself refused the action: the account is off that kind until the hold lifts) or limit_hold (a hold of another cause); null while not held."
                        required:
                          - done
                          - limit
                          - hold
                          - hold_until
                          - hold_reason
                      inmails:
                        type: object
                        properties:
                          done:
                            type: integer
                            minimum: 0
                            description: "Done today of this kind, in gtm's day: everything the account did, whoever asked for it."
                          limit:
                            type: integer
                            nullable: true
                            description: Today's cap of this kind (gtm's smart limit); null when the pacing mirror holds none.
                          hold:
                            type: boolean
                            description: "Whether this kind is held right now: the dispatcher sends none of it until hold_until."
                          hold_until:
                            type: string
                            nullable: true
                            description: "ISO 8601 UTC: when the hold lifts; null while not held."
                          hold_reason:
                            type: string
                            nullable: true
                            description: "Why it is held: daily_limit_reached (the cap is spent, or gtm reported the day saturated; lifts at gtm's next day), linkedin_limit_hit (LinkedIn itself refused the action: the account is off that kind until the hold lifts) or limit_hold (a hold of another cause); null while not held."
                        required:
                          - done
                          - limit
                          - hold
                          - hold_until
                          - hold_reason
                      visits:
                        type: object
                        properties:
                          done:
                            type: integer
                            minimum: 0
                            description: "Done today of this kind, in gtm's day: everything the account did, whoever asked for it."
                          limit:
                            type: integer
                            nullable: true
                            description: Today's cap of this kind (gtm's smart limit); null when the pacing mirror holds none.
                          hold:
                            type: boolean
                            description: "Whether this kind is held right now: the dispatcher sends none of it until hold_until."
                          hold_until:
                            type: string
                            nullable: true
                            description: "ISO 8601 UTC: when the hold lifts; null while not held."
                          hold_reason:
                            type: string
                            nullable: true
                            description: "Why it is held: daily_limit_reached (the cap is spent, or gtm reported the day saturated; lifts at gtm's next day), linkedin_limit_hit (LinkedIn itself refused the action: the account is off that kind until the hold lifts) or limit_hold (a hold of another cause); null while not held."
                        required:
                          - done
                          - limit
                          - hold
                          - hold_until
                          - hold_reason
                        description: Profile visits.
                    required:
                      - synced_at
                      - invites
                      - messages
                      - inmails
                      - visits
                    description: TODAY on LinkedIn, as the pacing mirror of gtm's smart limits counts it, per action kind against its cap and with its hold; null on a sender profile with no LinkedIn account.
                  email:
                    type: object
                    nullable: true
                    properties:
                      sent:
                        type: integer
                        minimum: 0
                        description: The ledger's email sends done today, in the workspace's timezone.
                      limit:
                        type: integer
                        nullable: true
                        description: The sum of the live mailboxes' daily limits; null when no live mailbox states one.
                      mailboxes:
                        type: array
                        items:
                          type: object
                          properties:
                            email_account_sid:
                              type: string
                              description: The mailbox (em_ac_…).
                            sent:
                              type: integer
                              minimum: 0
                              description: Sent today from this mailbox, attributed by the mailbox a done task left from.
                          required:
                            - email_account_sid
                            - sent
                        description: "Each of the sender profile's mailboxes in the copy's order: the Email tab's \"N of M sent\"."
                    required:
                      - sent
                      - limit
                      - mailboxes
                    description: "TODAY by email, in the workspace's timezone: the ledger's sends against the sum of the live mailboxes' limits, and per mailbox; null on a sender profile with no mailbox."
                  period:
                    type: object
                    properties:
                      invites:
                        type: integer
                        minimum: 0
                      messages:
                        type: integer
                        minimum: 0
                      inmails:
                        type: integer
                        minimum: 0
                      emails:
                        type: integer
                        minimum: 0
                      visits:
                        type: integer
                        minimum: 0
                    required:
                      - invites
                      - messages
                      - inmails
                      - emails
                      - visits
                    description: The ledger's done sends and profile visits inside from..to, by kind (by finished_at).
                  week:
                    type: array
                    items:
                      type: object
                      properties:
                        date:
                          type: string
                          description: YYYY-MM-DD in the workspace's timezone.
                        actions:
                          type: integer
                          minimum: 0
                          description: Every done send-class task of that day.
                      required:
                        - date
                        - actions
                    description: "The last seven days in the workspace's timezone, oldest first, today last: every done send-class task an action."
                  last_action:
                    type: object
                    nullable: true
                    properties:
                      at:
                        type: string
                        description: "ISO 8601 UTC: when it finished."
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                          - linkedin_send_message
                          - linkedin_send_inmail
                          - linkedin_visit_profile
                          - linkedin_endorse_skills
                          - linkedin_withdraw_connection_request
                          - linkedin_like_latest_post
                          - linkedin_comment_latest_post
                          - email_send
                          - wait
                          - wait_for_event
                          - condition
                          - ab_test
                          - api_call
                          - ask_ai
                          - manual_task
                          - move_to_workflow
                          - add_tag
                          - remove_tag
                          - set_field
                          - change_sender
                          - run_column
                        description: "What it was: a send-class task (a connection request, a message, an InMail, a profile visit, an endorsement, a withdrawal, a like, a comment or an email); the orchestration-class values of the vocabulary never appear here."
                    required:
                      - at
                      - type
                    description: The latest done send-class task of the last 30 days; null past that.
                  workflow_records_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                    description: "The journeys pinned to this sender profile (WorkflowRecordCounts over sender_profile_sid, full scope): total_count and groups.status, the enrollment funnel (active, waiting, paused_on_reply, waiting_limit, blocked, ...), the live load. See ./workflow_records.md."
                  workflow_tasks_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                    description: "The tasks that name this sender profile (WorkflowTaskCounts over sender_profile_sid, full scope): total_count and groups.status (pending, scheduled, dispatched, done, failed, ...), the queue shape. See ./workflow_tasks.md."
                required:
                  - sid
                  - linkedin
                  - email
                  - period
                  - week
                  - last_action
                  - workflow_records_counts
                  - workflow_tasks_counts
              description: One row per sid asked that names a sender profile of the team, in no fixed order.
          required:
            - sender_profiles
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ResetPipelineStagesDerivationRequest:
      type: object
      description: Request body of `reset_pipeline_stages_derivation`.
      properties:
        company_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_co_
            description: Company sid (cr_co_…).
          minItems: 1
          description: The companies to unpin, at least one. A non-company sid is rejected. The backend states no upper bound, but each entry is its own transaction plus its own re-derive job, so keep a call to a few hundred.
      required:
        - company_sids
    ResetPipelineStagesDerivationResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            reset_count:
              type: integer
              minimum: 0
              description: "Companies processed. A company that was not pinned counts too: it is re-derived either way."
          required:
            - reset_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ResetPlaytableFieldValueResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            object_sid:
              type: string
            playtable_field_sid:
              type: string
            value:
              type: string
              nullable: true
            is_value_from_formula:
              type: boolean
            original_value:
              type: string
              nullable: true
              description: "The system-produced value the FIRST manual overwrite snapshotted, what reset restores; null unless is_overwritten. The list surface nulls it like meta: read it on get, update, write and reset."
            is_overwritten:
              type: boolean
              description: "The current value is a manual write over a system-produced one: the edited marker, and the one state reset accepts."
            is_not_valid:
              type: boolean
              description: A manually written value that could not be converted to the column's type (text in a number column), stored raw and flagged; system writers coerce or null instead.
            status:
              type: string
              enum:
                - empty
                - queued
                - running
                - done
                - error
                - run_condition_not_met
            cost:
              type: number
              nullable: true
            provider_sid:
              type: string
              nullable: true
            meta:
              type: object
              nullable: true
              properties:
                run_sid:
                  type: string
                  nullable: true
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      step_index:
                        type: number
                      tool_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - success
                          - failed
                          - skipped
                      cost:
                        type: number
                      error:
                        type: string
                        nullable: true
                      finished_at:
                        type: string
                        nullable: true
                      verdict:
                        type: string
                        nullable: true
                      email:
                        type: string
                        nullable: true
                    required:
                      - step_index
                      - tool_sid
                      - status
                      - cost
                      - error
                      - finished_at
              required:
                - run_sid
                - steps
            error_msg:
              type: string
              nullable: true
            finished_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - object_sid
            - playtable_field_sid
            - value
            - is_value_from_formula
            - original_value
            - is_overwritten
            - is_not_valid
            - status
            - cost
            - provider_sid
            - meta
            - error_msg
            - finished_at
            - created_at
            - updated_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    RestartWorkflowRecordRequest:
      type: object
      description: Request body of `restart_workflow_record`.
      properties:
        mode:
          type: string
          enum:
            - from_start
            - from_current
          description: "from_start (default): the journey begins at the published version's entry step. from_current: it keeps the step it is on (the entry when the published version no longer has that step)."
        sender_profile_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: An explicit sender profile for the restarted journey; it must be in the workflow's sender pool (422 otherwise). Absent = the workflow's rotation strategy picks again.
        reason:
          type: string
          maxLength: 512
          description: Free-form; stored in the workflow_restarted activity and the log only - not on the row.
    RestartWorkflowRecordResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            workflow_sid:
              type: string
              description: wf_wf_… owning workflow; DB-UNIQUE together with people_sid - one row per (workflow, person) pair, forever - see ./workflows.md.
            workflow_version_sid:
              type: string
              description: wf_vr_… version pinned at enrollment - the record executes that step graph even after newer publishes - see ./workflow_versions.md.
            people_sid:
              type: string
              description: cr_pp_… the enrolled person; second half of the DB-UNIQUE pair - see ./people.md.
            entered_via_source_sid:
              type: string
              description: wf_sr_… entry point that produced the row (immutable audit) - see ./workflow_sources.md.
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… sender pinned at enrollment; null when the version has no send steps; re-resolved at next dispatch if the profile is deleted - see ./sender_profiles.md.
            current_step_id:
              type: number
              description: Small int step id inside the pinned version steps JSON (server-assigned, immutable, never reused) - a JSON node pointer, not a sid or row.
            status:
              type: string
              enum:
                - waiting_limit
                - blocked
                - active
                - waiting
                - paused_on_reply
                - paused_manual
                - paused_blocked
                - failed
                - completed
                - exited
            entered_at:
              type: string
              nullable: true
            touches_done:
              type: integer
              minimum: 0
            rotations_done:
              type: integer
              minimum: 0
            error_code:
              type: string
              nullable: true
              description: Machine code of the last failure, from the failing task result (max 64).
            error_message:
              type: string
              nullable: true
              description: Human-readable detail of the last failure (max 1024).
            last_touch_at:
              type: string
              description: ISO 8601 UTC - last step advance or status change; the staleness clock.
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once when status enters a terminal state; null while live.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - people_sid
            - entered_via_source_sid
            - sender_profile_sid
            - current_step_id
            - status
            - entered_at
            - touches_done
            - rotations_done
            - error_code
            - error_message
            - last_touch_at
            - finished_at
            - created_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            restarted_from:
              type: string
              description: The status the journey had before the restart (completed, exited, failed, active, waiting, paused_on_reply, paused_manual).
            cancelled_tasks_count:
              type: integer
              minimum: 0
              description: pending/scheduled tasks of this record cancelled in the same transaction before the first step was planned again.
            re_entered_count:
              type: integer
              minimum: 0
              description: How many times this journey has been started over in all, this one included.
            current_step_id:
              type: integer
              description: "The step the journey stands on now: the entry step, or the kept one on from_current."
          required:
            - restarted_from
            - cancelled_tasks_count
            - re_entered_count
            - current_step_id
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ResumeWorkflowRecordRequest:
      type: object
      description: Request body of `resume_workflow_record`.
      properties:
        reason:
          type: string
          maxLength: 512
          description: Free-form; stored in the workflow-records.resumed event payload only - not on the row.
    ResumeWorkflowRecordResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            workflow_sid:
              type: string
              description: wf_wf_… owning workflow; DB-UNIQUE together with people_sid - one row per (workflow, person) pair, forever - see ./workflows.md.
            workflow_version_sid:
              type: string
              description: wf_vr_… version pinned at enrollment - the record executes that step graph even after newer publishes - see ./workflow_versions.md.
            people_sid:
              type: string
              description: cr_pp_… the enrolled person; second half of the DB-UNIQUE pair - see ./people.md.
            entered_via_source_sid:
              type: string
              description: wf_sr_… entry point that produced the row (immutable audit) - see ./workflow_sources.md.
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… sender pinned at enrollment; null when the version has no send steps; re-resolved at next dispatch if the profile is deleted - see ./sender_profiles.md.
            current_step_id:
              type: number
              description: Small int step id inside the pinned version steps JSON (server-assigned, immutable, never reused) - a JSON node pointer, not a sid or row.
            status:
              type: string
              enum:
                - waiting_limit
                - blocked
                - active
                - waiting
                - paused_on_reply
                - paused_manual
                - paused_blocked
                - failed
                - completed
                - exited
            entered_at:
              type: string
              nullable: true
            touches_done:
              type: integer
              minimum: 0
            rotations_done:
              type: integer
              minimum: 0
            error_code:
              type: string
              nullable: true
              description: Machine code of the last failure, from the failing task result (max 64).
            error_message:
              type: string
              nullable: true
              description: Human-readable detail of the last failure (max 1024).
            last_touch_at:
              type: string
              description: ISO 8601 UTC - last step advance or status change; the staleness clock.
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once when status enters a terminal state; null while live.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - people_sid
            - entered_via_source_sid
            - sender_profile_sid
            - current_step_id
            - status
            - entered_at
            - touches_done
            - rotations_done
            - error_code
            - error_message
            - last_touch_at
            - finished_at
            - created_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            already_active:
              type: boolean
              description: true = idempotent no-op (the record was not paused).
          required:
            - already_active
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    ResumeWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            tasks_released_count:
              type: integer
              minimum: 0
              description: Held scheduled tasks eligible for dispatch again.
          required:
            - tasks_released_count
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    RetryWorkflowTaskRequest:
      type: object
      description: Request body of `retry_workflow_task`.
      properties:
        reason:
          type: string
          maxLength: 512
          description: Why the step runs again - rides the workflow-records.resumed event payload when the record is revived (not on the row).
        resend_unverified:
          type: boolean
          nullable: true
          description: "For a send that failed send_unconfirmed (gtm-api could not tell whether it went out): true only after a person looked where it would show (the thread, Sent, the invitations, the post) and vouches it never arrived, since a second send may reach them twice."
    RetryWorkflowTaskResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              nullable: true
              description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
            workflow_version_sid:
              type: string
              nullable: true
              description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
            workflow_record_sid:
              type: string
              nullable: true
              description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
            people_sid:
              type: string
              description: The person (cr_pp_…), denormalized for the person timeline.
            step_id:
              type: integer
              nullable: true
              description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
            type:
              type: string
              enum:
                - linkedin_send_connection_request
                - linkedin_send_message
                - linkedin_send_inmail
                - linkedin_visit_profile
                - linkedin_endorse_skills
                - linkedin_withdraw_connection_request
                - email_send
                - wait
                - wait_for_event
                - condition
                - api_call
                - ask_ai
                - manual_task
                - linkedin_like_latest_post
                - linkedin_comment_latest_post
                - ab_test
                - move_to_workflow
                - add_tag
                - remove_tag
                - set_field
                - change_sender
                - run_column
              description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
            attempt:
              type: integer
              description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
            status:
              type: string
              enum:
                - pending
                - scheduled
                - dispatched
                - done
                - failed
                - skipped
                - skipped_reply
                - skipped_stoplisted
                - cancelled
                - expired
              description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
            initiator:
              type: string
              enum:
                - workflow_record
                - play
                - user
              description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
            play_sid:
              type: string
              nullable: true
              description: The play that bore the task (pt_pl_…); null on a journey's task.
            trigger_activity_sid:
              type: string
              nullable: true
              description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
            act:
              type: object
              nullable: true
              properties:
                do:
                  type: string
                  enum:
                    - send_message
                    - add_to_workflow
                    - like
                    - comment
                    - ask
                  description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                about:
                  type: string
                  enum:
                    - birthday
                    - work_anniversary
                    - job_change
                    - post
                    - website_visit
                    - event
                  description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                actor_sid:
                  type: string
                  description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                target_workflow_sid:
                  type: string
                  description: add_to_workflow, and a question whose move or add names one.
                post_urn:
                  type: string
                  description: "like, comment: the post the act goes to (an activity URN)."
                reaction:
                  type: string
                  description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                options:
                  type: array
                  items:
                    type: string
                    enum:
                      - remove
                      - keep
                      - move
                      - add
                  description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                suggested:
                  type: string
                  enum:
                    - remove
                    - keep
                    - move
                    - add
                  description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
              required:
                - do
                - about
              description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
            sender_profile_sid:
              type: string
              nullable: true
              description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
            assignee_user_sid:
              type: string
              nullable: true
              description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
            scheduled_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
            timeout_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
            dispatched_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped on scheduled → dispatched.
            expires_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once on any terminal status.
            variables_snapshot:
              type: object
              nullable: true
              additionalProperties:
                type: string
              description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
            result:
              type: object
              nullable: true
              additionalProperties: {}
              description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
            error_code:
              type: string
              nullable: true
              description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
            error_message:
              type: string
              nullable: true
              description: Human detail of the failure (max 1024); null on a skip.
            previous_attempts:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  attempt:
                    type: integer
                    description: The attempt number it was.
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                  error_code:
                    type: string
                    nullable: true
                    description: Its reason token.
                  error_message:
                    type: string
                    nullable: true
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                required:
                  - attempt
                  - status
                  - error_code
                  - error_message
                  - result
                  - dispatched_at
                  - finished_at
              description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
            created_at:
              type: string
              description: ISO 8601 UTC - the planning moment.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - workflow_record_sid
            - people_sid
            - step_id
            - type
            - attempt
            - status
            - initiator
            - play_sid
            - trigger_activity_sid
            - act
            - sender_profile_sid
            - assignee_user_sid
            - scheduled_at
            - timeout_at
            - dispatched_at
            - expires_at
            - finished_at
            - variables_snapshot
            - result
            - error_code
            - error_message
            - previous_attempts
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            updated_workflow_record:
              type: object
              nullable: true
              additionalProperties: {}
              description: "The owning record AFTER the revival (WorkflowRecordDomain - entities/workflow_records.md): failed → active on this step, error cleared; a live, paused or gate-blocked (paused_blocked) record keeps its status. null for a play's task, which stands alone (re-armed and due now)."
          required:
            - updated_workflow_record
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    RotateDataSourceIngestKeyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            ingest_url:
              type: string
              description: "{api_base}/external/ingest/{ingest_key} with the new key. The previous URL already answers 404."
          required:
            - ingest_url
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    RunPlayResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
              description: Play sid (pt_pl_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…).
            playtable_sid:
              type: string
              description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
            catalog_key:
              type: string
              nullable: true
              enum:
                - keep_fresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
                - find_people_empty
                - top_up_thin
                - top_up_silent
                - top_up_no_reply
                - top_up_exhausted
                - find_decision_maker
                - reengage_dormant
                - reach_untouched
              description: The playbook entry the row was born from; null = a play saved from a view's filter.
            name:
              type: string
              description: The play's name, 1..255.
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What the audience selects: people, or company (accounts)."
            action_type:
              type: string
              enum:
                - find_people
                - add_to_workflow
                - refresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
              description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
            action:
              anyOf:
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                    per_company_limit:
                      type: integer
                      nullable: true
                      description: People taken per account, 1..25; null = the whole first page.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                    workflow_source_sid:
                      type: string
                      nullable: true
                      description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                  required:
                    - workflow_sid
                    - workflow_source_sid
                - type: object
                  properties:
                    moments:
                      type: object
                      properties:
                        birthday:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        work_anniversary:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        job_change:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                      description: A switch per moment with its own Do under it; a kind absent is off.
                  required:
                    - moments
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - remove_from_workflows
                        - move_to_workflow
                      description: For a person in a workflow whose title or company moved.
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                  required:
                    - do
                    - workflow_sid
                - type: object
                  properties:
                    like:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        reaction:
                          type: string
                          enum:
                            - ai
                            - like
                            - celebrate
                            - support
                            - love
                            - insightful
                            - funny
                          description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                      required:
                        - "on"
                        - reaction
                    comment:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        brief:
                          type: string
                          nullable: true
                          maxLength: 2000
                          description: What the AI writes the comment from; required while on.
                      required:
                        - "on"
                        - brief
                    per_person_weekly_cap:
                      type: integer
                      minimum: 1
                      maximum: 14
                      description: At most this many acts a week per person.
                    sender_profile_sid:
                      type: string
                      nullable: true
                      description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                  required:
                    - like
                    - comment
                    - per_person_weekly_cap
                    - sender_profile_sid
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - add_to_workflow
                      description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: required when the Do is a workflow."
                    pages:
                      type: array
                      nullable: true
                      items:
                        type: string
                      description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                  required:
                    - do
                    - workflow_sid
                    - pages
                - type: object
                  properties: {}
                  description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
              description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
            audience:
              description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
            watch:
              type: object
              nullable: true
              properties:
                profile_days:
                  anyOf:
                    - type: number
                      enum:
                        - 7
                    - type: number
                      enum:
                        - 14
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                company_days:
                  anyOf:
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The company page every N days: 30 | 90; null = not watched."
                posts_days:
                  anyOf:
                    - type: number
                      enum:
                        - 1
                    - type: number
                      enum:
                        - 3
                    - type: number
                      enum:
                        - 7
                    - {}
                  description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                moments:
                  type: boolean
                  description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
              required:
                - profile_days
                - company_days
                - posts_days
                - moments
              description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
            cadence:
              type: string
              enum:
                - manual
                - daily
              description: "manual: runs on run_play; daily: runs by itself every day while enabled."
            mode:
              type: string
              enum:
                - ask_me
                - automatic
              description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
            enabled:
              type: boolean
              description: The switch of a daily play; a manual play is always false.
            enabled_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Who gave the consent (switched the play on).
            enabled_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when."
            daily_credit_limit:
              type: integer
              nullable: true
              description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
            last_run_at:
              type: string
              nullable: true
              description: ISO 8601 UTC.
            last_run_counts:
              type: object
              nullable: true
              properties:
                matched:
                  type: integer
                  minimum: 0
                  description: Rows the audience matched at the run (the tab's count under the filter).
                acted:
                  type: integer
                  minimum: 0
                  description: Accounts appended to the queue, or people entered or re-entered.
                skipped:
                  type: integer
                  minimum: 0
                  description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                credits:
                  type: integer
                  minimum: 0
                  description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
              required:
                - matched
                - acted
                - skipped
                - credits
              description: What the last run did; null before the first run.
            next_run_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live.
          required:
            - sid
            - team_sid
            - playtable_sid
            - catalog_key
            - name
            - object_type
            - action_type
            - action
            - watch
            - cadence
            - mode
            - enabled
            - enabled_by
            - enabled_at
            - daily_credit_limit
            - last_run_at
            - last_run_counts
            - next_run_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            matched:
              type: integer
              minimum: 0
              description: Rows the audience matched at the run (the tab's count under the filter).
            acted:
              type: integer
              minimum: 0
              description: Accounts appended to the queue, or people entered or re-entered.
            skipped:
              type: integer
              minimum: 0
              description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
            credits:
              type: integer
              minimum: 0
              description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
          required:
            - matched
            - acted
            - skipped
            - credits
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    SearchActivitiesRequest:
      type: object
      description: Request body of `search_activities`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ac_
                  description: Activity sid (cr_ac_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ac_
                    description: Activity sid (cr_ac_…).
              additionalProperties: false
              description: Activity sid(s), cr_ac_ prefix (prefix-validated).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
              additionalProperties: false
              description: person | company.
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Timeline scope - cr_pp_/cr_co_ sid(s); `in` for company roll-ups (person sids from ./people.md search).
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object
                    - workflow
                    - ai_agent
                    - linkedin
                    - email
                    - website
                    - other
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
              additionalProperties: false
              description: Type-group filter - cheaper than a long type.in list.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object_created
                    - object_updated
                    - object_deleted
                    - object_playtable_changed
                    - object_pipeline_stage_changed
                    - tags_added
                    - tags_removed
                    - workflow_added
                    - workflow_restarted
                    - workflow_cancelled
                    - workflow_finished
                    - workflow_failed
                    - ai_agent_status_changed
                    - ai_agent_fact_saved
                    - linkedin_connection_request_sent
                    - linkedin_connection_request_accepted
                    - linkedin_connection_request_withdrawn
                    - linkedin_blocked
                    - linkedin_message_sent
                    - linkedin_inmail_sent
                    - linkedin_message_replied
                    - linkedin_inmail_replied
                    - linkedin_message_opened
                    - linkedin_link_clicked
                    - linkedin_post_liked
                    - linkedin_post_commented
                    - linkedin_profile_visited
                    - linkedin_skills_endorsed
                    - linkedin_invitation_received
                    - linkedin_invitation_accepted
                    - linkedin_invitation_ignored
                    - linkedin_invitation_expired
                    - linkedin_connection_removed
                    - linkedin_followed
                    - linkedin_message_reacted
                    - linkedin_message_deleted
                    - linkedin_profile_viewed_us
                    - email_sent
                    - email_replied
                    - email_opened
                    - email_bounced
                    - email_link_clicked
                    - email_unsubscribed
                    - email_complained
                    - website_visited
                    - website_key_page_visited
                    - website_form_submitted
                    - website_event
                    - manual_task_completed
                    - note_left
                    - object_enriched
                    - object_data_changed
                    - linkedin_job_changed
                    - linkedin_post_published
                    - linkedin_birthday
                    - linkedin_work_anniversary
                    - linkedin_profile_followed
                    - linkedin_post_engaged
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
              additionalProperties: false
              description: Exact fact kinds.
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                is_null:
                  type: boolean
              additionalProperties: false
              description: wf_wf_ sid(s); is_null:true = facts outside any workflow.
            workflow_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
                is_null:
                  type: boolean
              additionalProperties: false
              description: The step id (within its workflow) the fact was produced by; is_null:true = facts outside any step.
            occurred_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object. Ignored on metrics - period owns the window.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
              additionalProperties: false
              description: "A table's feed: the facts of its live people and the website facts of the accounts they work at. eq only."
            play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: "What plays caused: the people their find_people sources created (object_created) and the journeys their workflow sources began or started over (workflow_added, workflow_restarted). A non-empty in only."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                  minItems: 1
                is_null:
                  type: boolean
              additionalProperties: false
              description: The sender profile a fact came through (ub_sp_). A fact no sender profile made (website, CRM, workflow) never passes this leaf, leave it out to keep them; is_null true keeps only such facts. One of eq, non-empty in or is_null; another prefix is a 422.
            act_state:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting
                    - done
                    - none
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting
                      - done
                      - none
              additionalProperties: false
              description: waiting = a task waits on the event (a draft, a question, a failed act); done = handled, nothing waiting (a task of any status names it, an act left its fact, a wait woke); none = nothing touched it, never a kind no play handles. eq or non-empty in.
            acted_play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: The events those plays acted on, by a task or a fact naming the event. A non-empty in only.
            involved_sender_profile_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
              additionalProperties: false
              description: The facts stamped with those sender profiles, and the events a task or a fact of theirs answers (a post carries no sender profile; the comment drafted on it does). A non-empty in only.
            involved_workflow_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: "One campaign's events: the events of the people who hold or held a record of those workflows (a left journey counts) and the facts those workflows wrote. Wider than workflow_sid, which keeps the workflow's own facts alone. A non-empty in only."
            act_do:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - like
                      - comment
                      - send_message
                      - ask
                      - add_to_workflow
              additionalProperties: false
              description: "What an act did about the event, by a DONE task's act.do or the act's fact: like = linkedin_post_liked, comment = linkedin_post_commented, send_message = linkedin_message_sent; ask and add_to_workflow by the task alone. A non-empty in only."
            field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: "The facts a column's pull wrote, read off payload.field_sid (object_enriched, object_data_changed, linkedin_job_changed, linkedin_post_published carry it): with object_sid, one cell's history. eq or a non-empty in; a sid outside pt_fd_ is a 422."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range on when the fact reached the ledger, which can be long after it happened (a history walk). New since I looked = created_at gt seen_at with an occurred_at floor (seen_at minus 3 days); when it happened = occurred_at. On metrics too.
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - person
              - company
              - play_acts
              - person_journey
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - occurred_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchActivitiesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Activity sid (cr_ac_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  object_type:
                    type: string
                    enum:
                      - person
                      - company
                    description: "Which object the fact is about: person | company."
                  object_sid:
                    type: string
                    description: cr_pp_… (person) or cr_co_… (company) - the object the fact attaches to.
                  category:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
                    description: The type's group - derived from type by the fixed server-side map; stored for indexed channel filters.
                  type:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
                    description: 56-value fact vocabulary; past-tense fact label, not a state.
                  payload:
                    anyOf:
                      - type: object
                        properties:
                          origin:
                            type: string
                            enum:
                              - recheck
                              - catch_up
                            description: Where the change was seen.
                          changes:
                            type: array
                            items:
                              type: object
                              properties:
                                key:
                                  type: string
                                  maxLength: 128
                                  description: The answer's path (headline, company.name).
                                label:
                                  type: string
                                  maxLength: 128
                                  description: The word the row shows for it.
                                old:
                                  description: The value before.
                                new:
                                  description: The value after.
                              required:
                                - key
                                - label
                            minItems: 1
                            description: The title and the company, old and new, with every other key field that moved beside them.
                          field_sid:
                            type: string
                            nullable: true
                            description: pt_fd_… the column that re-checked; null from the catch-up feed.
                          column:
                            type: string
                            nullable: true
                            description: The column's name at the time; null from the catch-up feed.
                          source:
                            type: string
                            nullable: true
                            enum:
                              - linkedin_profile
                              - company_page
                              - work_email
                              - phone
                              - posts
                              - people
                              - api
                            description: What was read; null from the catch-up feed.
                          sender_profile_sid:
                            type: string
                            nullable: true
                            description: ub_sp_… the sender profile whose catch-up feed carried the card; null on a re-check.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: The gtm LinkedIn account that read the card; null on a re-check.
                        required:
                          - origin
                          - changes
                      - type: object
                        properties:
                          field_sid:
                            type: string
                            description: pt_fd_… the column that pulled.
                          column:
                            type: string
                            description: The column's name at the time.
                          source:
                            type: string
                            enum:
                              - linkedin_profile
                              - company_page
                              - work_email
                              - phone
                              - posts
                              - people
                              - api
                            description: What was read.
                          changes:
                            type: array
                            items:
                              type: object
                              properties:
                                key:
                                  type: string
                                  maxLength: 128
                                  description: The answer's path (headline, company.name).
                                label:
                                  type: string
                                  maxLength: 128
                                  description: The word the row shows for it.
                                old:
                                  description: The value before.
                                new:
                                  description: The value after.
                              required:
                                - key
                                - label
                            minItems: 1
                            description: Every key field that moved, old and new.
                        required:
                          - field_sid
                          - column
                          - source
                          - changes
                      - type: object
                        properties:
                          field_sid:
                            type: string
                            description: pt_fd_… the column that pulled - see ./playtable_fields.md.
                          column:
                            type: string
                            description: The column's name at the time.
                          source:
                            type: string
                            enum:
                              - linkedin_profile
                              - company_page
                              - work_email
                              - phone
                              - posts
                              - people
                              - api
                            description: What was read.
                          first:
                            type: boolean
                            description: "true = Enriched: the first pull of this column for the row that came back with an answer; false = Re-checked, every later one, changes or not."
                          outcome:
                            type: string
                            enum:
                              - found
                              - nothing_found
                              - not_verified
                            description: What came back.
                          fields:
                            type: integer
                            minimum: 0
                            description: How many of the answer's fields carried a value.
                          from_cache:
                            type: boolean
                            nullable: true
                            description: true when the answer came from the cache rather than the network.
                          credits:
                            type: number
                            nullable: true
                            minimum: 0
                            description: What the pull cost, in credits.
                          run_sid:
                            type: string
                            nullable: true
                            description: pt_rn_… the run that made the pull - see ./playtable_runs.md.
                          values:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                key:
                                  type: string
                                  description: The key field's path in the answer (a search's is `value`).
                                label:
                                  type: string
                                  description: "The word the row shows: Name, Headline, Title, Company, Location; Name, Industry, Size, Headquarters, Website; Work email; Phone."
                                value:
                                  type: string
                                  description: The value as a change compares it, at most 500 characters.
                              required:
                                - key
                                - label
                                - value
                            maxItems: 8
                            description: "The source's key fields that carry a value in this answer, in the source's order (2026-10-15): what the Enriched row's tree shows. [] when the answer held none (a search that found nothing); null for posts, people and api, which name no key fields; absent on facts written before."
                          verdict:
                            type: string
                            nullable: true
                            description: The email verifier's word on the address a work email search kept (valid, catch_all, unknown, risky; catch_all, unknown and risky make the outcome not_verified); null for every other source and when no verifier spoke.
                        required:
                          - field_sid
                          - column
                          - source
                          - first
                          - outcome
                          - fields
                      - type: object
                        properties:
                          activity_urn:
                            type: string
                            description: The post's activity URN, the one a Like or a comment addresses.
                          kind:
                            type: string
                            enum:
                              - post
                              - repost_with_comment
                            description: The person's own post, or a repost with their own words.
                          excerpt:
                            type: string
                            description: The post's text cut at 140 characters, the whitespace flattened; may be empty.
                          text:
                            type: string
                            nullable: true
                            maxLength: 3000
                            description: The whole post, its line breaks kept, 3000 characters at most (2026-10-15); absent on older facts.
                          post_urn:
                            type: string
                            nullable: true
                            description: The post's share or ugcPost URN, when it has one.
                          posted_at:
                            type: string
                            nullable: true
                            description: ISO 8601 UTC - when the post was published, as the network said.
                          field_sid:
                            type: string
                            nullable: true
                            description: pt_fd_… the column that read the posts; null when a workflow step's read wrote the fact.
                          column:
                            type: string
                            nullable: true
                            description: The column's name at the time.
                          likes:
                            type: integer
                            minimum: 0
                            description: The network's count at the read.
                          comments:
                            type: integer
                            minimum: 0
                            description: The network's count at the read.
                          reposts:
                            type: integer
                            minimum: 0
                            description: The network's count at the read.
                          images:
                            type: integer
                            minimum: 0
                            description: How many images the post carries; their copies come with the re-host, never a URL here.
                          reactions:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: integer
                              minimum: 0
                            description: The count by reaction kind as the read names the kinds (LIKE, EMPATHY, PRAISE, INTEREST, APPRECIATION, ENTERTAINMENT), 2026-10-15; null when the read carried none.
                        required:
                          - activity_urn
                          - kind
                          - excerpt
                          - likes
                          - comments
                          - reposts
                          - images
                      - type: object
                        properties:
                          activity_urn:
                            type: string
                            description: The watched post's activity URN, never a URL.
                          kind:
                            type: string
                            enum:
                              - reaction
                              - comment
                              - reshare
                            description: A reaction, a comment or a reshare.
                          data_source_sid:
                            type: string
                            description: ds_sc_… the engagers source that saw it - see ./data_sources.md.
                          reaction:
                            type: string
                            nullable: true
                            description: The reaction's name (like, celebrate, …) when the kind is a reaction.
                          author_name:
                            type: string
                            nullable: true
                            description: The post author's name, for the row.
                          excerpt:
                            type: string
                            nullable: true
                            description: The post's text cut at 140 characters, for the row.
                          engaged_at:
                            type: string
                            nullable: true
                            description: ISO 8601 UTC - when the engagement happened, when the network said.
                        required:
                          - activity_urn
                          - kind
                          - data_source_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          year:
                            type: integer
                            description: "The year the card is for: the dedup key with the kind."
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: The gtm LinkedIn account that read the card.
                          card_sid:
                            type: string
                            nullable: true
                            description: The feed card's URN.
                          text:
                            type: string
                            nullable: true
                            description: The card's own words, for the row.
                        required:
                          - sender_profile_sid
                          - year
                      - type: object
                        properties:
                          playtable_sid:
                            type: string
                            nullable: true
                            description: pt_tb_… table the object landed in - see ./playtables.md.
                          data_source_sid:
                            type: string
                            nullable: true
                            description: ds_sc_… source that produced the object - see ./data_sources.md.
                          data_source_item_sid:
                            type: string
                            nullable: true
                            description: ds_it_… item the object was promoted from - see ./data_source_items.md.
                          tags:
                            type: array
                            nullable: true
                            items: {}
                            description: Tags attached at creation; element shape deferred in research (see tags_added for the {sid, name} snapshot convention).
                          qualified:
                            type: boolean
                            nullable: true
                            description: "true = born from an item of a data source whose Check on save was on, so the record passed the source's criterion (2026-10-15). null otherwise (no gate, a hand row, the rows born before the stamp); never false: a record the gate turns away is never born."
                        required:
                          - playtable_sid
                          - data_source_sid
                          - data_source_item_sid
                          - tags
                      - type: object
                        properties:
                          fields:
                            type: array
                            items:
                              type: string
                            description: Changed field names.
                          old:
                            type: object
                            additionalProperties: {}
                            description: Previous values, keyed by field.
                          new:
                            type: object
                            additionalProperties: {}
                            description: New values, keyed by field.
                        required:
                          - fields
                          - old
                          - new
                      - type: object
                        properties:
                          old:
                            type: string
                            description: pt_tb_… membership before the move.
                          new:
                            type: string
                            description: pt_tb_… membership after the move.
                          data_source_sid:
                            type: string
                            nullable: true
                            description: ds_sc_… when a source import triggered the move.
                        required:
                          - old
                          - new
                          - data_source_sid
                      - type: object
                        properties:
                          name:
                            type: string
                            description: Tombstone snapshot - object display name at deletion time.
                        required:
                          - name
                      - type: object
                        properties:
                          tags:
                            type: array
                            items:
                              type: object
                              properties:
                                sid:
                                  type: string
                                  description: cr_tg_… tag - see ./tags.md.
                                name:
                                  type: string
                                  description: Tag name snapshot at event time.
                              required:
                                - sid
                                - name
                            description: Tags added/removed in this change, with name snapshots.
                        required:
                          - tags
                      - type: object
                        properties:
                          reason:
                            type: string
                            nullable: true
                            description: Human-readable cancellation reason.
                        required:
                          - reason
                      - type: object
                        properties:
                          reason:
                            type: string
                            description: Human-readable failure reason.
                        required:
                          - reason
                      - type: object
                        properties:
                          old:
                            type: string
                            description: Previous AI SDR status (Messaging-owned vocabulary).
                          new:
                            type: string
                            description: New AI SDR status.
                          message_sid:
                            type: string
                            nullable: true
                            description: External Messaging message that triggered the change; null when none.
                          channel:
                            type: string
                            nullable: true
                            description: Channel the status change relates to (Messaging-owned); null when not channel-bound.
                        required:
                          - old
                          - new
                          - message_sid
                          - channel
                      - type: object
                        properties:
                          fact:
                            type: string
                            maxLength: 64
                            description: The fact as the Playbook question names it ("Channel", "Their tool").
                          question:
                            type: string
                            maxLength: 255
                            description: The question in the agent's words.
                          answer:
                            type: string
                            maxLength: 512
                            description: The lead's answer, clamped server-side; untrusted text.
                          conversation_sid:
                            type: string
                            description: The unibox thread it was learned on (ub_cv_...).
                          run_sid:
                            type: string
                            nullable: true
                            description: The dialog turn that heard it (ub_rn_...); null when unknown.
                          changed:
                            type: boolean
                            description: true when it replaced an earlier answer to the same question on this thread.
                        required:
                          - fact
                          - question
                          - answer
                          - conversation_sid
                          - run_sid
                          - changed
                      - type: object
                        properties:
                          workflow_task_sid:
                            type: string
                            description: wf_tk_… completed manual task - see ./workflow_tasks.md (legacy task_uuid).
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account, when the task was LinkedIn-scoped.
                        required:
                          - workflow_task_sid
                          - sender_profile_sid
                          - linkedin_account_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          invitation_sid:
                            type: string
                            description: ln_ci_… the gtm invitation row.
                          note:
                            type: string
                            nullable: true
                            description: The lead's invitation text; null when none.
                          source:
                            type: string
                            nullable: true
                            description: How the end was learned, action | sync; null on the receipt.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - invitation_sid
                          - note
                          - source
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          connection_sid:
                            type: string
                            description: ln_cn_… the gtm connection row that was severed.
                          removal_kind:
                            type: string
                            nullable: true
                            description: removed (the lead removed us) | blocked (the account was blocked); null when unknown.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - connection_sid
                          - removal_kind
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          block_log_sid:
                            type: string
                            description: "The gtm linkedin-account-block-log row: the verdict, permanent for the account and the person."
                          connection_sid:
                            type: string
                            nullable: true
                            description: ln_cn_… the connection the block closed, when they were one; null otherwise.
                          activity_log_sid:
                            type: string
                            nullable: true
                            description: ln_al_… the read of gtm's activity log that established the block; null when unknown.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - block_log_sid
                          - connection_sid
                          - activity_log_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          follower_sid:
                            type: string
                            description: ln_fw_… the gtm follower row.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - follower_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          emoji:
                            type: string
                            description: The reaction, as LinkedIn reports it.
                          count:
                            type: integer
                            nullable: true
                            description: How many of the lead's side reacted with it; null when unknown.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - emoji
                          - count
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: "ub_sp_… the sender profile whose profile was looked at (the one the collector named: one sid on unibox and on the playtables copy) - see ./sender_profiles.md."
                          times_seen:
                            type: integer
                            minimum: 1
                            description: "How many runs of the collector listed the viewer: the first sighting and every re-view since."
                          first_seen_at:
                            type: string
                            description: "ISO 8601 UTC: when the collector first saw this viewer on this sender profile; the fact's occurred_at on the first sighting."
                          is_return:
                            type: boolean
                            description: True on a re-sighting after thirty days of absence (a second fact under a dated key); false on the first sighting.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: The gtm account the list was read on; null when unknown.
                          viewed_at_text:
                            type: string
                            nullable: true
                            description: The relative text LinkedIn printed last ("2 days ago"); null when none.
                          display_name:
                            type: string
                            nullable: true
                            description: The viewer's name as the list printed it at that moment; null when none.
                          headline:
                            type: string
                            nullable: true
                            description: The viewer's headline as the list printed it; null when none.
                        required:
                          - sender_profile_sid
                          - times_seen
                          - first_seen_at
                          - is_return
                          - linkedin_account_sid
                          - viewed_at_text
                          - display_name
                          - headline
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          mailbox_sid:
                            type: string
                            nullable: true
                            description: External Messaging mailbox.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          bounce_log_sid:
                            type: string
                            nullable: true
                            description: em_bl_… gtm's bounce log row behind the complaint; null when it did not ride the event.
                        required:
                          - sender_profile_sid
                          - mailbox_sid
                          - message_sid
                          - bounce_log_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            nullable: true
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                          connected_at:
                            type: string
                            description: ISO 8601 UTC - when the connection was accepted.
                          note_delivered:
                            type: boolean
                            nullable: true
                            description: "Whether the invite's note reached the thread as its first message at the accept (LinkedIn delivers it then, 2026-09-26): true when the invite went through the ledger with a note, false without one or when no invite of ours went (an already-connected accept), null when no ledger task sent the invite. With the messages sent, the base of the messages' reply rate."
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - template_sid
                          - connected_at
                          - note_delivered
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          endorsed_count:
                            type: integer
                            minimum: 0
                            description: Number of skills endorsed.
                          skills:
                            type: array
                            items:
                              type: string
                            description: Endorsed skill names.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - endorsed_count
                          - skills
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            nullable: true
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                          tracking_id:
                            type: string
                            description: Tracking id of the clicked link.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - template_sid
                          - tracking_id
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                          replied_message_sid:
                            type: string
                            nullable: true
                            description: Our message that was replied to; null when not resolvable.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - template_sid
                          - replied_message_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - template_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                          message_sid:
                            type: string
                            nullable: true
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                          - message_sid
                          - template_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: The gtm LinkedIn account that followed.
                        required:
                          - sender_profile_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          linkedin_account_sid:
                            type: string
                            nullable: true
                            description: External Messaging LinkedIn account.
                        required:
                          - sender_profile_sid
                          - linkedin_account_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          mailbox_sid:
                            type: string
                            nullable: true
                            description: External Messaging mailbox.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                          replied_message_sid:
                            type: string
                            nullable: true
                            description: Our message that was replied to; null when not resolvable.
                        required:
                          - sender_profile_sid
                          - mailbox_sid
                          - message_sid
                          - template_sid
                          - replied_message_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          mailbox_sid:
                            type: string
                            nullable: true
                            description: External Messaging mailbox.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          template_sid:
                            type: string
                            nullable: true
                            description: External Messaging template; null when no template was used.
                        required:
                          - sender_profile_sid
                          - mailbox_sid
                          - message_sid
                          - template_sid
                      - type: object
                        properties:
                          sender_profile_sid:
                            type: string
                            description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                          mailbox_sid:
                            type: string
                            nullable: true
                            description: External Messaging mailbox.
                          message_sid:
                            type: string
                            description: External Messaging message id (legacy email_uuid/message_uuid).
                          bounce_type:
                            type: string
                            nullable: true
                            description: hard | soft | policy, gtm's classification (2026-09-28); null on facts written before it.
                        required:
                          - sender_profile_sid
                          - mailbox_sid
                          - message_sid
                          - bounce_type
                      - type: object
                        properties:
                          session_sid:
                            type: string
                            description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                          site_sid:
                            type: string
                            description: sg_si_... the registered site the visit landed on.
                          attribution:
                            type: string
                            description: "How the owner was named: code (the person code in our link), identified (an identify call or a form), fingerprint (the device), manual (a bind by hand), company_code (the company code in our link) and company_network (the visitor's network), both with the company as the object. The signals service's vocabulary, stored as told."
                          entry_path:
                            type: string
                            nullable: true
                            description: The path of the first page view, with its query.
                          referrer_type:
                            type: string
                            nullable: true
                            description: direct | internal | search | social | email | ads | referral | ai_assistant | unknown.
                          utm_source:
                            type: string
                            nullable: true
                          utm_campaign:
                            type: string
                            nullable: true
                          landing_code_used:
                            type: boolean
                            nullable: true
                            description: "A code in our link named the owner: the person code (attribution code) or the company code (company_code)."
                          visitor_sid:
                            type: string
                            nullable: true
                            description: sg_wv_... the browser behind the visit.
                        required:
                          - session_sid
                          - site_sid
                          - attribution
                      - type: object
                        properties:
                          session_sid:
                            type: string
                            description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                          key_page_sid:
                            type: string
                            description: sg_kp_... the key page whose pattern matched.
                          key:
                            type: string
                            description: The key page's slug (pricing, demo, signup, contact, or one the team added).
                          path:
                            type: string
                            nullable: true
                            description: The path that matched the pattern.
                        required:
                          - session_sid
                          - key_page_sid
                          - key
                      - type: object
                        properties:
                          session_sid:
                            type: string
                            description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                          form:
                            type: string
                            description: The form's name as the site reported it.
                          visitor_sid:
                            type: string
                            nullable: true
                            description: sg_wv_... the browser the form was submitted from.
                        required:
                          - session_sid
                          - form
                      - type: object
                        properties:
                          session_sid:
                            type: string
                            description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                          event:
                            type: string
                            description: The registered event name, as the site sent it.
                          props:
                            anyOf:
                              - type: object
                                additionalProperties: {}
                              - type: array
                                items: {}
                              - {}
                            description: The event's properties as sent, 50 keys at most; [] when empty.
                        required:
                          - session_sid
                          - event
                      - type: object
                        properties:
                          note_sid:
                            type: string
                            description: cr_nt_… the note - see ./notes.md (legacy note_uuid).
                        required:
                          - note_sid
                      - type: object
                        additionalProperties: {}
                      - type: array
                        items: {}
                    description: Per-type references (sids, tracking ids, reasons) - never message bodies. Shape keyed by the sibling type field.
                  workflow_sid:
                    type: string
                    nullable: true
                    description: wf_wf_… when a workflow produced the fact - see ./workflows.md; null otherwise.
                  workflow_step_id:
                    type: integer
                    nullable: true
                    minimum: 0
                    description: Step id inside the version's steps JSON - see ./workflow_versions.md step-id contract.
                  workflow_record_sid:
                    type: string
                    nullable: true
                    description: wf_rc_… enrollment that produced the fact - see ./workflow_records.md.
                  external_sid:
                    type: string
                    nullable: true
                    description: Messaging event id (max 64) - ingest dedup key; null on in-process rows.
                  occurred_at:
                    type: string
                    description: ISO 8601 UTC - fact time at source; the timeline sort key.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Recording actor; actor_type=system on ingested rows.
                  created_at:
                    type: string
                    description: ISO 8601 UTC - row write time (ingest lag vs occurred_at possible).
                  updated_at:
                    type: string
                    description: ISO 8601 UTC - always equals created_at (no update path).
                required:
                  - sid
                  - team_sid
                  - object_type
                  - object_sid
                  - category
                  - type
                  - payload
                  - workflow_sid
                  - workflow_step_id
                  - workflow_record_sid
                  - external_sid
                  - occurred_at
                  - created_by
                  - created_at
                  - updated_at
              included:
                type: object
                properties:
                  person:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: PeopleDomain row (cr_pp_…) - see ./people.md; present on object_type=person rows when requested.
                  company:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: CompanyDomain row (cr_co_…) - see ./companies.md; present on object_type=company rows when requested.
                  play_acts:
                    type: object
                    properties:
                      tasks:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                          required:
                            - sid
                        description: "The workflow tasks naming this row as their trigger (WorkflowTaskDomain rows, see ./workflow_tasks.md), any status, oldest first: a play's (a draft waiting, a reaction sent, a question answered), a person's act by hand (initiator user, 2026-10-15), a journey's Like or comment on the post its read picked (2026-10-15). A journey's wait is the journey instead."
                      facts:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                          required:
                            - sid
                        description: "The facts an act left naming this row as their trigger (ActivityDomain rows), oldest first: the comment, the message, the journey entered or left."
                      plays:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^pt_pl_
                            name:
                              type: string
                            catalog_key:
                              type: string
                              nullable: true
                              description: The playbook entry the play was born from (PlayCatalogKeyEnum); null for a play saved from a view.
                            action_type:
                              type: string
                              enum:
                                - find_people
                                - add_to_workflow
                                - refresh
                                - congratulate
                                - on_job_change
                                - engage_posts
                                - on_website_visit
                            deleted_at:
                              type: string
                              nullable: true
                              description: ISO 8601 UTC when the play was deleted; its name still reads.
                          required:
                            - sid
                            - name
                            - catalog_key
                            - action_type
                            - deleted_at
                        description: Every play the row, its tasks, its facts and its passes name, deleted ones included so the name still reads.
                      journey:
                        type: object
                        nullable: true
                        properties:
                          workflow_sid:
                            type: string
                          workflow_record_sid:
                            type: string
                          record_status:
                            type: string
                            nullable: true
                            enum:
                              - waiting_limit
                              - blocked
                              - active
                              - waiting
                              - paused_on_reply
                              - paused_manual
                              - paused_blocked
                              - failed
                              - completed
                              - exited
                            description: The journey's status now; null only when the record is gone.
                          workflow_name:
                            type: string
                            nullable: true
                            description: The workflow's name, read with the deleted ones (2026-10-15); null only when the row is gone.
                          next:
                            type: object
                            nullable: true
                            properties:
                              step_id:
                                type: integer
                              step_ordinal:
                                type: integer
                                nullable: true
                                minimum: 0
                                exclusiveMinimum: true
                                description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                              step_count:
                                type: integer
                                nullable: true
                                minimum: 0
                                exclusiveMinimum: true
                                description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                              step_type:
                                type: string
                                nullable: true
                                description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                              status:
                                type: string
                                enum:
                                  - pending
                                  - scheduled
                                  - dispatched
                                  - done
                                  - failed
                                  - skipped
                                  - skipped_reply
                                  - skipped_stoplisted
                                  - cancelled
                                  - expired
                              at:
                                type: string
                                description: "ISO 8601 UTC: finished_at, else scheduled_at, else created_at."
                              text:
                                type: string
                                nullable: true
                                description: The words the task sends (its message, comment or email body as rendered, perhaps edited since), 2026-10-15; null for a step that sends nothing.
                            required:
                              - step_id
                              - step_ordinal
                              - step_count
                              - step_type
                              - status
                              - at
                              - text
                            description: The record's first task after the wait (another wait or a play's question skipped), whatever its status; null when nothing follows yet.
                        required:
                          - workflow_sid
                          - workflow_record_sid
                          - record_status
                          - workflow_name
                          - next
                        description: "The workflow that acted on the event: a journey's wait_for_event the event woke (the wait names it as its trigger), with the step that followed. Null when no journey waited on it."
                      records:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            workflow_sid:
                              type: string
                            status:
                              type: string
                              enum:
                                - waiting_limit
                                - blocked
                                - active
                                - waiting
                                - paused_on_reply
                                - paused_manual
                                - paused_blocked
                                - failed
                                - completed
                                - exited
                            current_step_id:
                              type: integer
                              nullable: true
                            step_ordinal:
                              type: integer
                              nullable: true
                              minimum: 0
                              exclusiveMinimum: true
                              description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                            step_count:
                              type: integer
                              nullable: true
                              minimum: 0
                              exclusiveMinimum: true
                              description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                            step_type:
                              type: string
                              nullable: true
                              description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                          required:
                            - workflow_sid
                            - status
                            - current_step_id
                            - step_ordinal
                            - step_count
                            - step_type
                        description: The journeys the row's play tasks ask about (a question names its record), keyed by workflow_record_sid, each with its current step's place. An empty object when none.
                      passes:
                        type: array
                        items:
                          type: object
                          properties:
                            play_sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^pt_pl_
                              description: The play that passed; named in plays.
                            reason:
                              type: string
                              enum:
                                - outside_audience
                                - act_failed
                                - moment_off
                                - no_connected_sender_profile
                                - empty_message
                                - no_journey
                                - journey_moved_on
                                - nothing_to_do
                                - post_unnamed
                                - post_too_old
                                - weekly_cap
                                - no_sender_profile
                                - comment_not_written
                                - already_engaged
                                - page_not_watched
                                - workflow_unnamed
                                - already_in_workflow
                              description: Why it passed on the event (the newest run's reason).
                            at:
                              type: string
                              description: "ISO 8601 UTC: when a run last passed for this reason."
                          required:
                            - play_sid
                            - reason
                            - at
                        description: "Why a play that watches the event passed on it (2026-10-15), one per play: the moment off, nobody connected, the weekly cap, a post too old, the person outside the audience, another hand's Like or comment on the post already. Empty when no play passed."
                      acts_as:
                        type: object
                        nullable: true
                        properties:
                          sender_profile_sid:
                            type: string
                            minLength: 18
                            maxLength: 18
                            pattern: ^ub_sp_
                        required:
                          - sender_profile_sid
                        description: "The sender profile act_on_activity would act as when given none (2026-10-15): on a post the connected one, else the team's first that can; on any other person's event the one the fact came through, else the connected one. Null for a company's event or when nobody can."
                      invite:
                        type: object
                        nullable: true
                        properties:
                          sent_at:
                            type: string
                            description: "ISO 8601 UTC: when the invitation went out (the invite task's finished_at)."
                          workflow_sid:
                            type: string
                            nullable: true
                            description: The journey that sent it (wf_wf_).
                          workflow_record_sid:
                            type: string
                            nullable: true
                            description: Its record (wf_rc_).
                        required:
                          - sent_at
                          - workflow_sid
                          - workflow_record_sid
                        description: "On a linkedin_connection_request_accepted row (2026-10-16): the invitation the accept answers, the person's newest done linkedin_send_connection_request task finished before the accept (a deleted journey's too), so \"Accepted the invitation after N days\" reads off sent_at. Null for an invitation sent by hand or unknown, and null on every other type."
                    required:
                      - tasks
                      - facts
                      - plays
                      - journey
                      - records
                      - passes
                      - acts_as
                      - invite
                    description: "What was done about the row (2026-10-14, the Signals feed): present on every row when requested, with empty lists, a null journey, an empty records object, a null acts_as and a null invite where nothing acted. The act_state leaf reads the same rows."
                  person_journey:
                    type: object
                    nullable: true
                    properties:
                      workflow_sid:
                        type: string
                      workflow_name:
                        type: string
                        nullable: true
                        description: The workflow's name, read with the deleted ones; null only when the row is gone.
                      workflow_record_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - waiting_limit
                          - blocked
                          - active
                          - waiting
                          - paused_on_reply
                          - paused_manual
                          - paused_blocked
                          - failed
                          - completed
                          - exited
                        description: The record's status as stored (WorkflowRecordStatusEnum).
                      current_step_id:
                        type: integer
                      step_ordinal:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                      step_count:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                      step_type:
                        type: string
                        nullable: true
                        description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                      step_name:
                        type: string
                        nullable: true
                        description: The step's own name in the pinned version (the builder's label, 255 at most); null when the builder gave none.
                      entered_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the journey began; null while the row is held at the door."
                      finished_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the journey ended; null until a terminal status."
                    required:
                      - workflow_sid
                      - workflow_name
                      - workflow_record_sid
                      - status
                      - current_step_id
                      - step_ordinal
                      - step_count
                      - step_type
                      - step_name
                      - entered_at
                      - finished_at
                    description: "The person's current journey (2026-10-16, the feed's workflow chip): the newest workflow record of the row's person whatever became of it, its status, its current step's place and name in the pinned version, the workflow's name (deleted records and workflows included). On every row when requested; null on a company's row and on a person with no record."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Rows matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                category:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {value: count} per ActivityCategoryEnum value present in scope."
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {value: count} per ActivityTypeEnum value present in scope - the engagement-widget axis."
                object_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {person: n, company: m} row counts."
              required:
                - category
                - type
                - object_type
              description: One axis per ActivityGroupableFieldsEnum value (§4.17); PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchActivityObjectsRequest:
      type: object
      description: Request body of `search_activity_objects`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ac_
                  description: Activity sid (cr_ac_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ac_
                    description: Activity sid (cr_ac_…).
              additionalProperties: false
              description: Activity sid(s), cr_ac_ prefix (prefix-validated).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
              additionalProperties: false
              description: person | company.
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Timeline scope - cr_pp_/cr_co_ sid(s); `in` for company roll-ups (person sids from ./people.md search).
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object
                    - workflow
                    - ai_agent
                    - linkedin
                    - email
                    - website
                    - other
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
              additionalProperties: false
              description: Type-group filter - cheaper than a long type.in list.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object_created
                    - object_updated
                    - object_deleted
                    - object_playtable_changed
                    - object_pipeline_stage_changed
                    - tags_added
                    - tags_removed
                    - workflow_added
                    - workflow_restarted
                    - workflow_cancelled
                    - workflow_finished
                    - workflow_failed
                    - ai_agent_status_changed
                    - ai_agent_fact_saved
                    - linkedin_connection_request_sent
                    - linkedin_connection_request_accepted
                    - linkedin_connection_request_withdrawn
                    - linkedin_blocked
                    - linkedin_message_sent
                    - linkedin_inmail_sent
                    - linkedin_message_replied
                    - linkedin_inmail_replied
                    - linkedin_message_opened
                    - linkedin_link_clicked
                    - linkedin_post_liked
                    - linkedin_post_commented
                    - linkedin_profile_visited
                    - linkedin_skills_endorsed
                    - linkedin_invitation_received
                    - linkedin_invitation_accepted
                    - linkedin_invitation_ignored
                    - linkedin_invitation_expired
                    - linkedin_connection_removed
                    - linkedin_followed
                    - linkedin_message_reacted
                    - linkedin_message_deleted
                    - linkedin_profile_viewed_us
                    - email_sent
                    - email_replied
                    - email_opened
                    - email_bounced
                    - email_link_clicked
                    - email_unsubscribed
                    - email_complained
                    - website_visited
                    - website_key_page_visited
                    - website_form_submitted
                    - website_event
                    - manual_task_completed
                    - note_left
                    - object_enriched
                    - object_data_changed
                    - linkedin_job_changed
                    - linkedin_post_published
                    - linkedin_birthday
                    - linkedin_work_anniversary
                    - linkedin_profile_followed
                    - linkedin_post_engaged
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
              additionalProperties: false
              description: Exact fact kinds.
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                is_null:
                  type: boolean
              additionalProperties: false
              description: wf_wf_ sid(s); is_null:true = facts outside any workflow.
            workflow_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
                is_null:
                  type: boolean
              additionalProperties: false
              description: The step id (within its workflow) the fact was produced by; is_null:true = facts outside any step.
            occurred_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object. Ignored on metrics - period owns the window.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
              additionalProperties: false
              description: "A table's feed: the facts of its live people and the website facts of the accounts they work at. eq only."
            play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: "What plays caused: the people their find_people sources created (object_created) and the journeys their workflow sources began or started over (workflow_added, workflow_restarted). A non-empty in only."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                  minItems: 1
                is_null:
                  type: boolean
              additionalProperties: false
              description: The sender profile a fact came through (ub_sp_). A fact no sender profile made (website, CRM, workflow) never passes this leaf, leave it out to keep them; is_null true keeps only such facts. One of eq, non-empty in or is_null; another prefix is a 422.
            act_state:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting
                    - done
                    - none
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting
                      - done
                      - none
              additionalProperties: false
              description: waiting = a task waits on the event (a draft, a question, a failed act); done = handled, nothing waiting (a task of any status names it, an act left its fact, a wait woke); none = nothing touched it, never a kind no play handles. eq or non-empty in.
            acted_play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: The events those plays acted on, by a task or a fact naming the event. A non-empty in only.
            involved_sender_profile_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
              additionalProperties: false
              description: The facts stamped with those sender profiles, and the events a task or a fact of theirs answers (a post carries no sender profile; the comment drafted on it does). A non-empty in only.
            involved_workflow_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: "One campaign's events: the events of the people who hold or held a record of those workflows (a left journey counts) and the facts those workflows wrote. Wider than workflow_sid, which keeps the workflow's own facts alone. A non-empty in only."
            act_do:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - like
                      - comment
                      - send_message
                      - ask
                      - add_to_workflow
              additionalProperties: false
              description: "What an act did about the event, by a DONE task's act.do or the act's fact: like = linkedin_post_liked, comment = linkedin_post_commented, send_message = linkedin_message_sent; ask and add_to_workflow by the task alone. A non-empty in only."
            field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: "The facts a column's pull wrote, read off payload.field_sid (object_enriched, object_data_changed, linkedin_job_changed, linkedin_post_published carry it): with object_sid, one cell's history. eq or a non-empty in; a sid outside pt_fd_ is a 422."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range on when the fact reached the ledger, which can be long after it happened (a history walk). New since I looked = created_at gt seen_at with an occurred_at floor (seen_at minus 3 days); when it happened = occurred_at. On metrics too.
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - person
              - company
              - play_acts
              - person_journey
          description: Relations to attach to every item; omit for the bare rows.
        page_size:
          type: integer
          minimum: 0
          maximum: 200
          description: 0..200, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
        fresh:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ac_
                  description: Activity sid (cr_ac_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ac_
                    description: Activity sid (cr_ac_…).
              additionalProperties: false
              description: Activity sid(s), cr_ac_ prefix (prefix-validated).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
              additionalProperties: false
              description: person | company.
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Timeline scope - cr_pp_/cr_co_ sid(s); `in` for company roll-ups (person sids from ./people.md search).
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object
                    - workflow
                    - ai_agent
                    - linkedin
                    - email
                    - website
                    - other
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object
                      - workflow
                      - ai_agent
                      - linkedin
                      - email
                      - website
                      - other
              additionalProperties: false
              description: Type-group filter - cheaper than a long type.in list.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - object_created
                    - object_updated
                    - object_deleted
                    - object_playtable_changed
                    - object_pipeline_stage_changed
                    - tags_added
                    - tags_removed
                    - workflow_added
                    - workflow_restarted
                    - workflow_cancelled
                    - workflow_finished
                    - workflow_failed
                    - ai_agent_status_changed
                    - ai_agent_fact_saved
                    - linkedin_connection_request_sent
                    - linkedin_connection_request_accepted
                    - linkedin_connection_request_withdrawn
                    - linkedin_blocked
                    - linkedin_message_sent
                    - linkedin_inmail_sent
                    - linkedin_message_replied
                    - linkedin_inmail_replied
                    - linkedin_message_opened
                    - linkedin_link_clicked
                    - linkedin_post_liked
                    - linkedin_post_commented
                    - linkedin_profile_visited
                    - linkedin_skills_endorsed
                    - linkedin_invitation_received
                    - linkedin_invitation_accepted
                    - linkedin_invitation_ignored
                    - linkedin_invitation_expired
                    - linkedin_connection_removed
                    - linkedin_followed
                    - linkedin_message_reacted
                    - linkedin_message_deleted
                    - linkedin_profile_viewed_us
                    - email_sent
                    - email_replied
                    - email_opened
                    - email_bounced
                    - email_link_clicked
                    - email_unsubscribed
                    - email_complained
                    - website_visited
                    - website_key_page_visited
                    - website_form_submitted
                    - website_event
                    - manual_task_completed
                    - note_left
                    - object_enriched
                    - object_data_changed
                    - linkedin_job_changed
                    - linkedin_post_published
                    - linkedin_birthday
                    - linkedin_work_anniversary
                    - linkedin_profile_followed
                    - linkedin_post_engaged
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - object_created
                      - object_updated
                      - object_deleted
                      - object_playtable_changed
                      - object_pipeline_stage_changed
                      - tags_added
                      - tags_removed
                      - workflow_added
                      - workflow_restarted
                      - workflow_cancelled
                      - workflow_finished
                      - workflow_failed
                      - ai_agent_status_changed
                      - ai_agent_fact_saved
                      - linkedin_connection_request_sent
                      - linkedin_connection_request_accepted
                      - linkedin_connection_request_withdrawn
                      - linkedin_blocked
                      - linkedin_message_sent
                      - linkedin_inmail_sent
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - linkedin_message_opened
                      - linkedin_link_clicked
                      - linkedin_post_liked
                      - linkedin_post_commented
                      - linkedin_profile_visited
                      - linkedin_skills_endorsed
                      - linkedin_invitation_received
                      - linkedin_invitation_accepted
                      - linkedin_invitation_ignored
                      - linkedin_invitation_expired
                      - linkedin_connection_removed
                      - linkedin_followed
                      - linkedin_message_reacted
                      - linkedin_message_deleted
                      - linkedin_profile_viewed_us
                      - email_sent
                      - email_replied
                      - email_opened
                      - email_bounced
                      - email_link_clicked
                      - email_unsubscribed
                      - email_complained
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                      - website_event
                      - manual_task_completed
                      - note_left
                      - object_enriched
                      - object_data_changed
                      - linkedin_job_changed
                      - linkedin_post_published
                      - linkedin_birthday
                      - linkedin_work_anniversary
                      - linkedin_profile_followed
                      - linkedin_post_engaged
              additionalProperties: false
              description: Exact fact kinds.
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                is_null:
                  type: boolean
              additionalProperties: false
              description: wf_wf_ sid(s); is_null:true = facts outside any workflow.
            workflow_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
                is_null:
                  type: boolean
              additionalProperties: false
              description: The step id (within its workflow) the fact was produced by; is_null:true = facts outside any step.
            occurred_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object. Ignored on metrics - period owns the window.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
              additionalProperties: false
              description: "A table's feed: the facts of its live people and the website facts of the accounts they work at. eq only."
            play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: "What plays caused: the people their find_people sources created (object_created) and the journeys their workflow sources began or started over (workflow_added, workflow_restarted). A non-empty in only."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                  minItems: 1
                is_null:
                  type: boolean
              additionalProperties: false
              description: The sender profile a fact came through (ub_sp_). A fact no sender profile made (website, CRM, workflow) never passes this leaf, leave it out to keep them; is_null true keeps only such facts. One of eq, non-empty in or is_null; another prefix is a 422.
            act_state:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting
                    - done
                    - none
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting
                      - done
                      - none
              additionalProperties: false
              description: waiting = a task waits on the event (a draft, a question, a failed act); done = handled, nothing waiting (a task of any status names it, an act left its fact, a wait woke); none = nothing touched it, never a kind no play handles. eq or non-empty in.
            acted_play_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
              additionalProperties: false
              description: The events those plays acted on, by a task or a fact naming the event. A non-empty in only.
            involved_sender_profile_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
              additionalProperties: false
              description: The facts stamped with those sender profiles, and the events a task or a fact of theirs answers (a post carries no sender profile; the comment drafted on it does). A non-empty in only.
            involved_workflow_sid:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: "One campaign's events: the events of the people who hold or held a record of those workflows (a left journey counts) and the facts those workflows wrote. Wider than workflow_sid, which keeps the workflow's own facts alone. A non-empty in only."
            act_do:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - like
                      - comment
                      - send_message
                      - ask
                      - add_to_workflow
              additionalProperties: false
              description: "What an act did about the event, by a DONE task's act.do or the act's fact: like = linkedin_post_liked, comment = linkedin_post_commented, send_message = linkedin_message_sent; ask and add_to_workflow by the task alone. A non-empty in only."
            field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: "The facts a column's pull wrote, read off payload.field_sid (object_enriched, object_data_changed, linkedin_job_changed, linkedin_post_published carry it): with object_sid, one cell's history. eq or a non-empty in; a sid outside pt_fd_ is a 422."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range on when the fact reached the ledger, which can be long after it happened (a history walk). New since I looked = created_at gt seen_at with an occurred_at floor (seen_at minus 3 days); when it happened = occurred_at. On metrics too.
          description: 'A second filter with the same leaves that marks facts inside `filter` (a fact is fresh when both keep it): "new since I looked" is created_at {gt: seen_at} with occurred_at {gt: seen_at minus three days}. No leaf marks nothing.'
        fresh_objects:
          type: string
          enum:
            - only
            - without
          description: only = list the objects holding a fresh fact; without = list the objects holding none. Absent lists every object. With no `fresh`, only lists nothing.
    SearchActivityObjectsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  object_type:
                    type: string
                    enum:
                      - person
                      - company
                    description: person | company.
                  object_sid:
                    type: string
                    description: "cr_pp_… (person) or cr_co_… (company): the row's key."
                  latest:
                    type: object
                    properties:
                      sid:
                        type: string
                        description: Activity sid (cr_ac_…).
                      team_sid:
                        type: string
                        description: Owning team (ts_tm_…, external - gs.service.id).
                      object_type:
                        type: string
                        enum:
                          - person
                          - company
                        description: "Which object the fact is about: person | company."
                      object_sid:
                        type: string
                        description: cr_pp_… (person) or cr_co_… (company) - the object the fact attaches to.
                      category:
                        type: string
                        enum:
                          - object
                          - workflow
                          - ai_agent
                          - linkedin
                          - email
                          - website
                          - other
                        description: The type's group - derived from type by the fixed server-side map; stored for indexed channel filters.
                      type:
                        type: string
                        enum:
                          - object_created
                          - object_updated
                          - object_deleted
                          - object_playtable_changed
                          - object_pipeline_stage_changed
                          - tags_added
                          - tags_removed
                          - workflow_added
                          - workflow_restarted
                          - workflow_cancelled
                          - workflow_finished
                          - workflow_failed
                          - ai_agent_status_changed
                          - ai_agent_fact_saved
                          - linkedin_connection_request_sent
                          - linkedin_connection_request_accepted
                          - linkedin_connection_request_withdrawn
                          - linkedin_blocked
                          - linkedin_message_sent
                          - linkedin_inmail_sent
                          - linkedin_message_replied
                          - linkedin_inmail_replied
                          - linkedin_message_opened
                          - linkedin_link_clicked
                          - linkedin_post_liked
                          - linkedin_post_commented
                          - linkedin_profile_visited
                          - linkedin_skills_endorsed
                          - linkedin_invitation_received
                          - linkedin_invitation_accepted
                          - linkedin_invitation_ignored
                          - linkedin_invitation_expired
                          - linkedin_connection_removed
                          - linkedin_followed
                          - linkedin_message_reacted
                          - linkedin_message_deleted
                          - linkedin_profile_viewed_us
                          - email_sent
                          - email_replied
                          - email_opened
                          - email_bounced
                          - email_link_clicked
                          - email_unsubscribed
                          - email_complained
                          - website_visited
                          - website_key_page_visited
                          - website_form_submitted
                          - website_event
                          - manual_task_completed
                          - note_left
                          - object_enriched
                          - object_data_changed
                          - linkedin_job_changed
                          - linkedin_post_published
                          - linkedin_birthday
                          - linkedin_work_anniversary
                          - linkedin_profile_followed
                          - linkedin_post_engaged
                        description: 56-value fact vocabulary; past-tense fact label, not a state.
                      payload:
                        anyOf:
                          - type: object
                            properties:
                              origin:
                                type: string
                                enum:
                                  - recheck
                                  - catch_up
                                description: Where the change was seen.
                              changes:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    key:
                                      type: string
                                      maxLength: 128
                                      description: The answer's path (headline, company.name).
                                    label:
                                      type: string
                                      maxLength: 128
                                      description: The word the row shows for it.
                                    old:
                                      description: The value before.
                                    new:
                                      description: The value after.
                                  required:
                                    - key
                                    - label
                                minItems: 1
                                description: The title and the company, old and new, with every other key field that moved beside them.
                              field_sid:
                                type: string
                                nullable: true
                                description: pt_fd_… the column that re-checked; null from the catch-up feed.
                              column:
                                type: string
                                nullable: true
                                description: The column's name at the time; null from the catch-up feed.
                              source:
                                type: string
                                nullable: true
                                enum:
                                  - linkedin_profile
                                  - company_page
                                  - work_email
                                  - phone
                                  - posts
                                  - people
                                  - api
                                description: What was read; null from the catch-up feed.
                              sender_profile_sid:
                                type: string
                                nullable: true
                                description: ub_sp_… the sender profile whose catch-up feed carried the card; null on a re-check.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: The gtm LinkedIn account that read the card; null on a re-check.
                            required:
                              - origin
                              - changes
                          - type: object
                            properties:
                              field_sid:
                                type: string
                                description: pt_fd_… the column that pulled.
                              column:
                                type: string
                                description: The column's name at the time.
                              source:
                                type: string
                                enum:
                                  - linkedin_profile
                                  - company_page
                                  - work_email
                                  - phone
                                  - posts
                                  - people
                                  - api
                                description: What was read.
                              changes:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    key:
                                      type: string
                                      maxLength: 128
                                      description: The answer's path (headline, company.name).
                                    label:
                                      type: string
                                      maxLength: 128
                                      description: The word the row shows for it.
                                    old:
                                      description: The value before.
                                    new:
                                      description: The value after.
                                  required:
                                    - key
                                    - label
                                minItems: 1
                                description: Every key field that moved, old and new.
                            required:
                              - field_sid
                              - column
                              - source
                              - changes
                          - type: object
                            properties:
                              field_sid:
                                type: string
                                description: pt_fd_… the column that pulled - see ./playtable_fields.md.
                              column:
                                type: string
                                description: The column's name at the time.
                              source:
                                type: string
                                enum:
                                  - linkedin_profile
                                  - company_page
                                  - work_email
                                  - phone
                                  - posts
                                  - people
                                  - api
                                description: What was read.
                              first:
                                type: boolean
                                description: "true = Enriched: the first pull of this column for the row that came back with an answer; false = Re-checked, every later one, changes or not."
                              outcome:
                                type: string
                                enum:
                                  - found
                                  - nothing_found
                                  - not_verified
                                description: What came back.
                              fields:
                                type: integer
                                minimum: 0
                                description: How many of the answer's fields carried a value.
                              from_cache:
                                type: boolean
                                nullable: true
                                description: true when the answer came from the cache rather than the network.
                              credits:
                                type: number
                                nullable: true
                                minimum: 0
                                description: What the pull cost, in credits.
                              run_sid:
                                type: string
                                nullable: true
                                description: pt_rn_… the run that made the pull - see ./playtable_runs.md.
                              values:
                                type: array
                                nullable: true
                                items:
                                  type: object
                                  properties:
                                    key:
                                      type: string
                                      description: The key field's path in the answer (a search's is `value`).
                                    label:
                                      type: string
                                      description: "The word the row shows: Name, Headline, Title, Company, Location; Name, Industry, Size, Headquarters, Website; Work email; Phone."
                                    value:
                                      type: string
                                      description: The value as a change compares it, at most 500 characters.
                                  required:
                                    - key
                                    - label
                                    - value
                                maxItems: 8
                                description: "The source's key fields that carry a value in this answer, in the source's order (2026-10-15): what the Enriched row's tree shows. [] when the answer held none (a search that found nothing); null for posts, people and api, which name no key fields; absent on facts written before."
                              verdict:
                                type: string
                                nullable: true
                                description: The email verifier's word on the address a work email search kept (valid, catch_all, unknown, risky; catch_all, unknown and risky make the outcome not_verified); null for every other source and when no verifier spoke.
                            required:
                              - field_sid
                              - column
                              - source
                              - first
                              - outcome
                              - fields
                          - type: object
                            properties:
                              activity_urn:
                                type: string
                                description: The post's activity URN, the one a Like or a comment addresses.
                              kind:
                                type: string
                                enum:
                                  - post
                                  - repost_with_comment
                                description: The person's own post, or a repost with their own words.
                              excerpt:
                                type: string
                                description: The post's text cut at 140 characters, the whitespace flattened; may be empty.
                              text:
                                type: string
                                nullable: true
                                maxLength: 3000
                                description: The whole post, its line breaks kept, 3000 characters at most (2026-10-15); absent on older facts.
                              post_urn:
                                type: string
                                nullable: true
                                description: The post's share or ugcPost URN, when it has one.
                              posted_at:
                                type: string
                                nullable: true
                                description: ISO 8601 UTC - when the post was published, as the network said.
                              field_sid:
                                type: string
                                nullable: true
                                description: pt_fd_… the column that read the posts; null when a workflow step's read wrote the fact.
                              column:
                                type: string
                                nullable: true
                                description: The column's name at the time.
                              likes:
                                type: integer
                                minimum: 0
                                description: The network's count at the read.
                              comments:
                                type: integer
                                minimum: 0
                                description: The network's count at the read.
                              reposts:
                                type: integer
                                minimum: 0
                                description: The network's count at the read.
                              images:
                                type: integer
                                minimum: 0
                                description: How many images the post carries; their copies come with the re-host, never a URL here.
                              reactions:
                                type: object
                                nullable: true
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                                description: The count by reaction kind as the read names the kinds (LIKE, EMPATHY, PRAISE, INTEREST, APPRECIATION, ENTERTAINMENT), 2026-10-15; null when the read carried none.
                            required:
                              - activity_urn
                              - kind
                              - excerpt
                              - likes
                              - comments
                              - reposts
                              - images
                          - type: object
                            properties:
                              activity_urn:
                                type: string
                                description: The watched post's activity URN, never a URL.
                              kind:
                                type: string
                                enum:
                                  - reaction
                                  - comment
                                  - reshare
                                description: A reaction, a comment or a reshare.
                              data_source_sid:
                                type: string
                                description: ds_sc_… the engagers source that saw it - see ./data_sources.md.
                              reaction:
                                type: string
                                nullable: true
                                description: The reaction's name (like, celebrate, …) when the kind is a reaction.
                              author_name:
                                type: string
                                nullable: true
                                description: The post author's name, for the row.
                              excerpt:
                                type: string
                                nullable: true
                                description: The post's text cut at 140 characters, for the row.
                              engaged_at:
                                type: string
                                nullable: true
                                description: ISO 8601 UTC - when the engagement happened, when the network said.
                            required:
                              - activity_urn
                              - kind
                              - data_source_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              year:
                                type: integer
                                description: "The year the card is for: the dedup key with the kind."
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: The gtm LinkedIn account that read the card.
                              card_sid:
                                type: string
                                nullable: true
                                description: The feed card's URN.
                              text:
                                type: string
                                nullable: true
                                description: The card's own words, for the row.
                            required:
                              - sender_profile_sid
                              - year
                          - type: object
                            properties:
                              playtable_sid:
                                type: string
                                nullable: true
                                description: pt_tb_… table the object landed in - see ./playtables.md.
                              data_source_sid:
                                type: string
                                nullable: true
                                description: ds_sc_… source that produced the object - see ./data_sources.md.
                              data_source_item_sid:
                                type: string
                                nullable: true
                                description: ds_it_… item the object was promoted from - see ./data_source_items.md.
                              tags:
                                type: array
                                nullable: true
                                items: {}
                                description: Tags attached at creation; element shape deferred in research (see tags_added for the {sid, name} snapshot convention).
                              qualified:
                                type: boolean
                                nullable: true
                                description: "true = born from an item of a data source whose Check on save was on, so the record passed the source's criterion (2026-10-15). null otherwise (no gate, a hand row, the rows born before the stamp); never false: a record the gate turns away is never born."
                            required:
                              - playtable_sid
                              - data_source_sid
                              - data_source_item_sid
                              - tags
                          - type: object
                            properties:
                              fields:
                                type: array
                                items:
                                  type: string
                                description: Changed field names.
                              old:
                                type: object
                                additionalProperties: {}
                                description: Previous values, keyed by field.
                              new:
                                type: object
                                additionalProperties: {}
                                description: New values, keyed by field.
                            required:
                              - fields
                              - old
                              - new
                          - type: object
                            properties:
                              old:
                                type: string
                                description: pt_tb_… membership before the move.
                              new:
                                type: string
                                description: pt_tb_… membership after the move.
                              data_source_sid:
                                type: string
                                nullable: true
                                description: ds_sc_… when a source import triggered the move.
                            required:
                              - old
                              - new
                              - data_source_sid
                          - type: object
                            properties:
                              name:
                                type: string
                                description: Tombstone snapshot - object display name at deletion time.
                            required:
                              - name
                          - type: object
                            properties:
                              tags:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    sid:
                                      type: string
                                      description: cr_tg_… tag - see ./tags.md.
                                    name:
                                      type: string
                                      description: Tag name snapshot at event time.
                                  required:
                                    - sid
                                    - name
                                description: Tags added/removed in this change, with name snapshots.
                            required:
                              - tags
                          - type: object
                            properties:
                              reason:
                                type: string
                                nullable: true
                                description: Human-readable cancellation reason.
                            required:
                              - reason
                          - type: object
                            properties:
                              reason:
                                type: string
                                description: Human-readable failure reason.
                            required:
                              - reason
                          - type: object
                            properties:
                              old:
                                type: string
                                description: Previous AI SDR status (Messaging-owned vocabulary).
                              new:
                                type: string
                                description: New AI SDR status.
                              message_sid:
                                type: string
                                nullable: true
                                description: External Messaging message that triggered the change; null when none.
                              channel:
                                type: string
                                nullable: true
                                description: Channel the status change relates to (Messaging-owned); null when not channel-bound.
                            required:
                              - old
                              - new
                              - message_sid
                              - channel
                          - type: object
                            properties:
                              fact:
                                type: string
                                maxLength: 64
                                description: The fact as the Playbook question names it ("Channel", "Their tool").
                              question:
                                type: string
                                maxLength: 255
                                description: The question in the agent's words.
                              answer:
                                type: string
                                maxLength: 512
                                description: The lead's answer, clamped server-side; untrusted text.
                              conversation_sid:
                                type: string
                                description: The unibox thread it was learned on (ub_cv_...).
                              run_sid:
                                type: string
                                nullable: true
                                description: The dialog turn that heard it (ub_rn_...); null when unknown.
                              changed:
                                type: boolean
                                description: true when it replaced an earlier answer to the same question on this thread.
                            required:
                              - fact
                              - question
                              - answer
                              - conversation_sid
                              - run_sid
                              - changed
                          - type: object
                            properties:
                              workflow_task_sid:
                                type: string
                                description: wf_tk_… completed manual task - see ./workflow_tasks.md (legacy task_uuid).
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account, when the task was LinkedIn-scoped.
                            required:
                              - workflow_task_sid
                              - sender_profile_sid
                              - linkedin_account_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              invitation_sid:
                                type: string
                                description: ln_ci_… the gtm invitation row.
                              note:
                                type: string
                                nullable: true
                                description: The lead's invitation text; null when none.
                              source:
                                type: string
                                nullable: true
                                description: How the end was learned, action | sync; null on the receipt.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - invitation_sid
                              - note
                              - source
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              connection_sid:
                                type: string
                                description: ln_cn_… the gtm connection row that was severed.
                              removal_kind:
                                type: string
                                nullable: true
                                description: removed (the lead removed us) | blocked (the account was blocked); null when unknown.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - connection_sid
                              - removal_kind
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              block_log_sid:
                                type: string
                                description: "The gtm linkedin-account-block-log row: the verdict, permanent for the account and the person."
                              connection_sid:
                                type: string
                                nullable: true
                                description: ln_cn_… the connection the block closed, when they were one; null otherwise.
                              activity_log_sid:
                                type: string
                                nullable: true
                                description: ln_al_… the read of gtm's activity log that established the block; null when unknown.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - block_log_sid
                              - connection_sid
                              - activity_log_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              follower_sid:
                                type: string
                                description: ln_fw_… the gtm follower row.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - follower_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              emoji:
                                type: string
                                description: The reaction, as LinkedIn reports it.
                              count:
                                type: integer
                                nullable: true
                                description: How many of the lead's side reacted with it; null when unknown.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - emoji
                              - count
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: "ub_sp_… the sender profile whose profile was looked at (the one the collector named: one sid on unibox and on the playtables copy) - see ./sender_profiles.md."
                              times_seen:
                                type: integer
                                minimum: 1
                                description: "How many runs of the collector listed the viewer: the first sighting and every re-view since."
                              first_seen_at:
                                type: string
                                description: "ISO 8601 UTC: when the collector first saw this viewer on this sender profile; the fact's occurred_at on the first sighting."
                              is_return:
                                type: boolean
                                description: True on a re-sighting after thirty days of absence (a second fact under a dated key); false on the first sighting.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: The gtm account the list was read on; null when unknown.
                              viewed_at_text:
                                type: string
                                nullable: true
                                description: The relative text LinkedIn printed last ("2 days ago"); null when none.
                              display_name:
                                type: string
                                nullable: true
                                description: The viewer's name as the list printed it at that moment; null when none.
                              headline:
                                type: string
                                nullable: true
                                description: The viewer's headline as the list printed it; null when none.
                            required:
                              - sender_profile_sid
                              - times_seen
                              - first_seen_at
                              - is_return
                              - linkedin_account_sid
                              - viewed_at_text
                              - display_name
                              - headline
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              mailbox_sid:
                                type: string
                                nullable: true
                                description: External Messaging mailbox.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              bounce_log_sid:
                                type: string
                                nullable: true
                                description: em_bl_… gtm's bounce log row behind the complaint; null when it did not ride the event.
                            required:
                              - sender_profile_sid
                              - mailbox_sid
                              - message_sid
                              - bounce_log_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                nullable: true
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                              connected_at:
                                type: string
                                description: ISO 8601 UTC - when the connection was accepted.
                              note_delivered:
                                type: boolean
                                nullable: true
                                description: "Whether the invite's note reached the thread as its first message at the accept (LinkedIn delivers it then, 2026-09-26): true when the invite went through the ledger with a note, false without one or when no invite of ours went (an already-connected accept), null when no ledger task sent the invite. With the messages sent, the base of the messages' reply rate."
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - template_sid
                              - connected_at
                              - note_delivered
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              endorsed_count:
                                type: integer
                                minimum: 0
                                description: Number of skills endorsed.
                              skills:
                                type: array
                                items:
                                  type: string
                                description: Endorsed skill names.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - endorsed_count
                              - skills
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                nullable: true
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                              tracking_id:
                                type: string
                                description: Tracking id of the clicked link.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - template_sid
                              - tracking_id
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                              replied_message_sid:
                                type: string
                                nullable: true
                                description: Our message that was replied to; null when not resolvable.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - template_sid
                              - replied_message_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - template_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                              message_sid:
                                type: string
                                nullable: true
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                              - message_sid
                              - template_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: The gtm LinkedIn account that followed.
                            required:
                              - sender_profile_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              linkedin_account_sid:
                                type: string
                                nullable: true
                                description: External Messaging LinkedIn account.
                            required:
                              - sender_profile_sid
                              - linkedin_account_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              mailbox_sid:
                                type: string
                                nullable: true
                                description: External Messaging mailbox.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                              replied_message_sid:
                                type: string
                                nullable: true
                                description: Our message that was replied to; null when not resolvable.
                            required:
                              - sender_profile_sid
                              - mailbox_sid
                              - message_sid
                              - template_sid
                              - replied_message_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              mailbox_sid:
                                type: string
                                nullable: true
                                description: External Messaging mailbox.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              template_sid:
                                type: string
                                nullable: true
                                description: External Messaging template; null when no template was used.
                            required:
                              - sender_profile_sid
                              - mailbox_sid
                              - message_sid
                              - template_sid
                          - type: object
                            properties:
                              sender_profile_sid:
                                type: string
                                description: ub_sp_… sender profile that acted - see ./sender_profiles.md.
                              mailbox_sid:
                                type: string
                                nullable: true
                                description: External Messaging mailbox.
                              message_sid:
                                type: string
                                description: External Messaging message id (legacy email_uuid/message_uuid).
                              bounce_type:
                                type: string
                                nullable: true
                                description: hard | soft | policy, gtm's classification (2026-09-28); null on facts written before it.
                            required:
                              - sender_profile_sid
                              - mailbox_sid
                              - message_sid
                              - bounce_type
                          - type: object
                            properties:
                              session_sid:
                                type: string
                                description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                              site_sid:
                                type: string
                                description: sg_si_... the registered site the visit landed on.
                              attribution:
                                type: string
                                description: "How the owner was named: code (the person code in our link), identified (an identify call or a form), fingerprint (the device), manual (a bind by hand), company_code (the company code in our link) and company_network (the visitor's network), both with the company as the object. The signals service's vocabulary, stored as told."
                              entry_path:
                                type: string
                                nullable: true
                                description: The path of the first page view, with its query.
                              referrer_type:
                                type: string
                                nullable: true
                                description: direct | internal | search | social | email | ads | referral | ai_assistant | unknown.
                              utm_source:
                                type: string
                                nullable: true
                              utm_campaign:
                                type: string
                                nullable: true
                              landing_code_used:
                                type: boolean
                                nullable: true
                                description: "A code in our link named the owner: the person code (attribution code) or the company code (company_code)."
                              visitor_sid:
                                type: string
                                nullable: true
                                description: sg_wv_... the browser behind the visit.
                            required:
                              - session_sid
                              - site_sid
                              - attribution
                          - type: object
                            properties:
                              session_sid:
                                type: string
                                description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                              key_page_sid:
                                type: string
                                description: sg_kp_... the key page whose pattern matched.
                              key:
                                type: string
                                description: The key page's slug (pricing, demo, signup, contact, or one the team added).
                              path:
                                type: string
                                nullable: true
                                description: The path that matched the pattern.
                            required:
                              - session_sid
                              - key_page_sid
                              - key
                          - type: object
                            properties:
                              session_sid:
                                type: string
                                description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                              form:
                                type: string
                                description: The form's name as the site reported it.
                              visitor_sid:
                                type: string
                                nullable: true
                                description: sg_wv_... the browser the form was submitted from.
                            required:
                              - session_sid
                              - form
                          - type: object
                            properties:
                              session_sid:
                                type: string
                                description: sg_ws_... the session in gs.service.signals (get_website_session reads its pages and events).
                              event:
                                type: string
                                description: The registered event name, as the site sent it.
                              props:
                                anyOf:
                                  - type: object
                                    additionalProperties: {}
                                  - type: array
                                    items: {}
                                  - {}
                                description: The event's properties as sent, 50 keys at most; [] when empty.
                            required:
                              - session_sid
                              - event
                          - type: object
                            properties:
                              note_sid:
                                type: string
                                description: cr_nt_… the note - see ./notes.md (legacy note_uuid).
                            required:
                              - note_sid
                          - type: object
                            additionalProperties: {}
                          - type: array
                            items: {}
                        description: Per-type references (sids, tracking ids, reasons) - never message bodies. Shape keyed by the sibling type field.
                      workflow_sid:
                        type: string
                        nullable: true
                        description: wf_wf_… when a workflow produced the fact - see ./workflows.md; null otherwise.
                      workflow_step_id:
                        type: integer
                        nullable: true
                        minimum: 0
                        description: Step id inside the version's steps JSON - see ./workflow_versions.md step-id contract.
                      workflow_record_sid:
                        type: string
                        nullable: true
                        description: wf_rc_… enrollment that produced the fact - see ./workflow_records.md.
                      external_sid:
                        type: string
                        nullable: true
                        description: Messaging event id (max 64) - ingest dedup key; null on in-process rows.
                      occurred_at:
                        type: string
                        description: ISO 8601 UTC - fact time at source; the timeline sort key.
                      created_by:
                        type: object
                        properties:
                          actor_type:
                            type: string
                            enum:
                              - user
                              - support
                              - api_key
                              - system
                              - agent
                          actor_sid:
                            type: string
                            nullable: true
                          team_sid:
                            type: string
                          actor_name:
                            type: string
                            nullable: true
                            description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                          oauth_client_sid:
                            type: string
                            nullable: true
                            description: The acting OAuth client (id_oc_*); null off the OAuth path.
                          reason:
                            type: string
                            nullable: true
                            description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                          permissions:
                            type: object
                            additionalProperties: {}
                            description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                          cluster_id:
                            type: integer
                            nullable: true
                            description: "Internal audit context: the cluster that served the write."
                          trace_id:
                            type: string
                            nullable: true
                            description: "Internal audit context: the trace id of the request that wrote the row."
                        required:
                          - actor_type
                          - actor_sid
                          - team_sid
                          - permissions
                        description: Recording actor; actor_type=system on ingested rows.
                      created_at:
                        type: string
                        description: ISO 8601 UTC - row write time (ingest lag vs occurred_at possible).
                      updated_at:
                        type: string
                        description: ISO 8601 UTC - always equals created_at (no update path).
                    required:
                      - sid
                      - team_sid
                      - object_type
                      - object_sid
                      - category
                      - type
                      - payload
                      - workflow_sid
                      - workflow_step_id
                      - workflow_record_sid
                      - external_sid
                      - occurred_at
                      - created_by
                      - created_at
                      - updated_at
                    description: The newest fact of the object under the filter, the ledger's own row, verbatim.
                  facts_count:
                    type: integer
                    minimum: 0
                    exclusiveMinimum: true
                    description: How many facts the filter keeps of the object.
                  fresh_count:
                    type: integer
                    minimum: 0
                    description: Of them, the facts the `fresh` filter keeps too; 0 when the request marked nothing.
                  recent_types:
                    type: array
                    items:
                      type: string
                      enum:
                        - object_created
                        - object_updated
                        - object_deleted
                        - object_playtable_changed
                        - object_pipeline_stage_changed
                        - tags_added
                        - tags_removed
                        - workflow_added
                        - workflow_restarted
                        - workflow_cancelled
                        - workflow_finished
                        - workflow_failed
                        - ai_agent_status_changed
                        - ai_agent_fact_saved
                        - linkedin_connection_request_sent
                        - linkedin_connection_request_accepted
                        - linkedin_connection_request_withdrawn
                        - linkedin_blocked
                        - linkedin_message_sent
                        - linkedin_inmail_sent
                        - linkedin_message_replied
                        - linkedin_inmail_replied
                        - linkedin_message_opened
                        - linkedin_link_clicked
                        - linkedin_post_liked
                        - linkedin_post_commented
                        - linkedin_profile_visited
                        - linkedin_skills_endorsed
                        - linkedin_invitation_received
                        - linkedin_invitation_accepted
                        - linkedin_invitation_ignored
                        - linkedin_invitation_expired
                        - linkedin_connection_removed
                        - linkedin_followed
                        - linkedin_message_reacted
                        - linkedin_message_deleted
                        - linkedin_profile_viewed_us
                        - email_sent
                        - email_replied
                        - email_opened
                        - email_bounced
                        - email_link_clicked
                        - email_unsubscribed
                        - email_complained
                        - website_visited
                        - website_key_page_visited
                        - website_form_submitted
                        - website_event
                        - manual_task_completed
                        - note_left
                        - object_enriched
                        - object_data_changed
                        - linkedin_job_changed
                        - linkedin_post_published
                        - linkedin_birthday
                        - linkedin_work_anniversary
                        - linkedin_profile_followed
                        - linkedin_post_engaged
                    maxItems: 3
                    description: The types of the object's newest facts under the filter, newest first, at most 3; the first is latest.type.
                required:
                  - object_type
                  - object_sid
                  - latest
                  - facts_count
                  - fresh_count
                  - recent_types
              included:
                type: object
                properties:
                  person:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: PeopleDomain row (cr_pp_…) - see ./people.md; present on object_type=person rows when requested.
                  company:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: CompanyDomain row (cr_co_…) - see ./companies.md; present on object_type=company rows when requested.
                  play_acts:
                    type: object
                    properties:
                      tasks:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                          required:
                            - sid
                        description: "The workflow tasks naming this row as their trigger (WorkflowTaskDomain rows, see ./workflow_tasks.md), any status, oldest first: a play's (a draft waiting, a reaction sent, a question answered), a person's act by hand (initiator user, 2026-10-15), a journey's Like or comment on the post its read picked (2026-10-15). A journey's wait is the journey instead."
                      facts:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                          required:
                            - sid
                        description: "The facts an act left naming this row as their trigger (ActivityDomain rows), oldest first: the comment, the message, the journey entered or left."
                      plays:
                        type: array
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^pt_pl_
                            name:
                              type: string
                            catalog_key:
                              type: string
                              nullable: true
                              description: The playbook entry the play was born from (PlayCatalogKeyEnum); null for a play saved from a view.
                            action_type:
                              type: string
                              enum:
                                - find_people
                                - add_to_workflow
                                - refresh
                                - congratulate
                                - on_job_change
                                - engage_posts
                                - on_website_visit
                            deleted_at:
                              type: string
                              nullable: true
                              description: ISO 8601 UTC when the play was deleted; its name still reads.
                          required:
                            - sid
                            - name
                            - catalog_key
                            - action_type
                            - deleted_at
                        description: Every play the row, its tasks, its facts and its passes name, deleted ones included so the name still reads.
                      journey:
                        type: object
                        nullable: true
                        properties:
                          workflow_sid:
                            type: string
                          workflow_record_sid:
                            type: string
                          record_status:
                            type: string
                            nullable: true
                            enum:
                              - waiting_limit
                              - blocked
                              - active
                              - waiting
                              - paused_on_reply
                              - paused_manual
                              - paused_blocked
                              - failed
                              - completed
                              - exited
                            description: The journey's status now; null only when the record is gone.
                          workflow_name:
                            type: string
                            nullable: true
                            description: The workflow's name, read with the deleted ones (2026-10-15); null only when the row is gone.
                          next:
                            type: object
                            nullable: true
                            properties:
                              step_id:
                                type: integer
                              step_ordinal:
                                type: integer
                                nullable: true
                                minimum: 0
                                exclusiveMinimum: true
                                description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                              step_count:
                                type: integer
                                nullable: true
                                minimum: 0
                                exclusiveMinimum: true
                                description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                              step_type:
                                type: string
                                nullable: true
                                description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                              status:
                                type: string
                                enum:
                                  - pending
                                  - scheduled
                                  - dispatched
                                  - done
                                  - failed
                                  - skipped
                                  - skipped_reply
                                  - skipped_stoplisted
                                  - cancelled
                                  - expired
                              at:
                                type: string
                                description: "ISO 8601 UTC: finished_at, else scheduled_at, else created_at."
                              text:
                                type: string
                                nullable: true
                                description: The words the task sends (its message, comment or email body as rendered, perhaps edited since), 2026-10-15; null for a step that sends nothing.
                            required:
                              - step_id
                              - step_ordinal
                              - step_count
                              - step_type
                              - status
                              - at
                              - text
                            description: The record's first task after the wait (another wait or a play's question skipped), whatever its status; null when nothing follows yet.
                        required:
                          - workflow_sid
                          - workflow_record_sid
                          - record_status
                          - workflow_name
                          - next
                        description: "The workflow that acted on the event: a journey's wait_for_event the event woke (the wait names it as its trigger), with the step that followed. Null when no journey waited on it."
                      records:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            workflow_sid:
                              type: string
                            status:
                              type: string
                              enum:
                                - waiting_limit
                                - blocked
                                - active
                                - waiting
                                - paused_on_reply
                                - paused_manual
                                - paused_blocked
                                - failed
                                - completed
                                - exited
                            current_step_id:
                              type: integer
                              nullable: true
                            step_ordinal:
                              type: integer
                              nullable: true
                              minimum: 0
                              exclusiveMinimum: true
                              description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                            step_count:
                              type: integer
                              nullable: true
                              minimum: 0
                              exclusiveMinimum: true
                              description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                            step_type:
                              type: string
                              nullable: true
                              description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                          required:
                            - workflow_sid
                            - status
                            - current_step_id
                            - step_ordinal
                            - step_count
                            - step_type
                        description: The journeys the row's play tasks ask about (a question names its record), keyed by workflow_record_sid, each with its current step's place. An empty object when none.
                      passes:
                        type: array
                        items:
                          type: object
                          properties:
                            play_sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^pt_pl_
                              description: The play that passed; named in plays.
                            reason:
                              type: string
                              enum:
                                - outside_audience
                                - act_failed
                                - moment_off
                                - no_connected_sender_profile
                                - empty_message
                                - no_journey
                                - journey_moved_on
                                - nothing_to_do
                                - post_unnamed
                                - post_too_old
                                - weekly_cap
                                - no_sender_profile
                                - comment_not_written
                                - already_engaged
                                - page_not_watched
                                - workflow_unnamed
                                - already_in_workflow
                              description: Why it passed on the event (the newest run's reason).
                            at:
                              type: string
                              description: "ISO 8601 UTC: when a run last passed for this reason."
                          required:
                            - play_sid
                            - reason
                            - at
                        description: "Why a play that watches the event passed on it (2026-10-15), one per play: the moment off, nobody connected, the weekly cap, a post too old, the person outside the audience, another hand's Like or comment on the post already. Empty when no play passed."
                      acts_as:
                        type: object
                        nullable: true
                        properties:
                          sender_profile_sid:
                            type: string
                            minLength: 18
                            maxLength: 18
                            pattern: ^ub_sp_
                        required:
                          - sender_profile_sid
                        description: "The sender profile act_on_activity would act as when given none (2026-10-15): on a post the connected one, else the team's first that can; on any other person's event the one the fact came through, else the connected one. Null for a company's event or when nobody can."
                      invite:
                        type: object
                        nullable: true
                        properties:
                          sent_at:
                            type: string
                            description: "ISO 8601 UTC: when the invitation went out (the invite task's finished_at)."
                          workflow_sid:
                            type: string
                            nullable: true
                            description: The journey that sent it (wf_wf_).
                          workflow_record_sid:
                            type: string
                            nullable: true
                            description: Its record (wf_rc_).
                        required:
                          - sent_at
                          - workflow_sid
                          - workflow_record_sid
                        description: "On a linkedin_connection_request_accepted row (2026-10-16): the invitation the accept answers, the person's newest done linkedin_send_connection_request task finished before the accept (a deleted journey's too), so \"Accepted the invitation after N days\" reads off sent_at. Null for an invitation sent by hand or unknown, and null on every other type."
                    required:
                      - tasks
                      - facts
                      - plays
                      - journey
                      - records
                      - passes
                      - acts_as
                      - invite
                    description: "What was done about the row (2026-10-14, the Signals feed): present on every row when requested, with empty lists, a null journey, an empty records object, a null acts_as and a null invite where nothing acted. The act_state leaf reads the same rows."
                  person_journey:
                    type: object
                    nullable: true
                    properties:
                      workflow_sid:
                        type: string
                      workflow_name:
                        type: string
                        nullable: true
                        description: The workflow's name, read with the deleted ones; null only when the row is gone.
                      workflow_record_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - waiting_limit
                          - blocked
                          - active
                          - waiting
                          - paused_on_reply
                          - paused_manual
                          - paused_blocked
                          - failed
                          - completed
                          - exited
                        description: The record's status as stored (WorkflowRecordStatusEnum).
                      current_step_id:
                        type: integer
                      step_ordinal:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: 1-based place of the step in the pinned version, depth first ("step 3 of 5"); null when the version does not have it.
                      step_count:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: Steps in the pinned version, nested ones and end steps counted; null with step_ordinal.
                      step_type:
                        type: string
                        nullable: true
                        description: "The step's type in the version (WorkflowStepTypeEnum: linkedin_send_message, email_send, condition, ...); null with step_ordinal."
                      step_name:
                        type: string
                        nullable: true
                        description: The step's own name in the pinned version (the builder's label, 255 at most); null when the builder gave none.
                      entered_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the journey began; null while the row is held at the door."
                      finished_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the journey ended; null until a terminal status."
                    required:
                      - workflow_sid
                      - workflow_name
                      - workflow_record_sid
                      - status
                      - current_step_id
                      - step_ordinal
                      - step_count
                      - step_type
                      - step_name
                      - entered_at
                      - finished_at
                    description: "The person's current journey (2026-10-16, the feed's workflow chip): the newest workflow record of the row's person whatever became of it, its status, its current step's place and name in the pinned version, the workflow's name (deleted records and workflows included). On every row when requested; null on a company's row and on a person with no record."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: The objects the request lists.
            facts_count:
              type: integer
              minimum: 0
              description: The facts the filter keeps of them.
            groups:
              type: object
              properties:
                category:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {value: count}: the listed objects holding a fact of that category. An object counts under every value it holds, so the values do not sum to total_count."
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {value: count}: the listed objects holding a fact of that type."
                object_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {person: n, company: m}."
                fresh:
                  type: object
                  properties:
                    "true":
                      type: integer
                      minimum: 0
                    "false":
                      type: integer
                      minimum: 0
                  required:
                    - "true"
                    - "false"
                  description: The listed objects split by whether they hold a fresh fact.
              required:
                - category
                - type
                - object_type
                - fresh
          required:
            - total_count
            - facts_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchCompaniesRequest:
      type: object
      description: Request body of `search_companies`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
              additionalProperties: false
              description: Prefix-validated cr_co_ sid(s).
            playtable_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every company tab passes { in: [<table>] }; array-overlap. nin answers the complement, memberless rows included."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The account's funnel bucket (one of seven), expanded on the server into the team's company stage sids of those categories: ask by name, never resolve the stages yourself. eq approaching = someone was invited or written to and nobody answered."
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the account, all must hold: its own visit and the account names rolled up over the people to work (disqualified or stoplisted people do not count). Never compose the roll-ups yourself. A person's or a thread's name is a 422."
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance (ds_sc_…).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap (any of); cr_tg_ sids - resolve labels via tags. nin answers the complement, untagged rows included.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact LinkedIn company id.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact page slug; fuzzy matching goes through q.
            domain:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Lowercased apex; is_null = enrichment gap.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact match; substring goes through q.
            q:
              type: string
              maxLength: 128
              description: Free text over name, domain, website, ln_nickname (ES full-text).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - people_counts
              - field_values
              - last_activities
              - notes
              - signals
              - freshness
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              anyOf:
                - type: string
                  enum:
                    - row_order
                    - created_at
                    - updated_at
                    - name
                - type: string
                  pattern: ^fields\.[a-z][a-z0-9_]{0,63}$
                  description: Custom column of the pinned playtable, by slug.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: Default asc for row_order, desc otherwise.
          required:
            - field
          description: One sort column with its direction; default row_order asc, the grid row order (a per-team arrival sequence, never a job title).
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
        filter_ast:
          description: "The §4.18 filter AST (the same tree the grid saves on a view): ANDed with `filter`; typed leaves over object attributes, record.<slug> cells, journey arrays, and the `signals` leaf (any of the catalog names the account carries)."
        sids_only:
          type: boolean
          description: "Answer the matching sids only (the grid's ids-only model): items carry {sid} and nothing else."
        semantic:
          type: object
          properties:
            field:
              type: string
              minLength: 8
              maxLength: 96
              pattern: ^record\.
              description: The semantic column, record.<slug>, whose value vectors are searched.
            query:
              type: string
              minLength: 1
              maxLength: 2048
              description: Natural-language query embedded and matched against the column.
            k:
              type: integer
              minimum: 1
              maximum: 500
              description: Nearest neighbours to keep before the filter applies. Default 100.
            min_score:
              type: number
              minimum: 0
              maximum: 1
              description: "The match floor on the score the rows come back with (0..1, cosine mapped as (1 + cos) / 2): a row below it is out, not last. Default: no floor, the k nearest stay."
          required:
            - field
            - query
          description: Semantic search over one embedded column (research §Filterable, the I5 engine); the result order is similarity.
    SearchCompaniesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sids:
                    type: array
                    items:
                      type: string
                    description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
                  data_source_sid:
                    type: string
                    nullable: true
                  data_source_type:
                    type: string
                    nullable: true
                  data_source_item_sid:
                    type: string
                    nullable: true
                  ln_id:
                    type: string
                    nullable: true
                    description: Numeric LinkedIn company id - strongest dedup key.
                  ln_nickname:
                    type: string
                    nullable: true
                    description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
                  context:
                    type: object
                    nullable: true
                    properties:
                      name:
                        type: string
                        nullable: true
                      picture_url:
                        type: string
                        nullable: true
                        description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                      website:
                        type: string
                        nullable: true
                        description: The full URL a source gave; domain on the row stays the identifier.
                      sources:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            kind:
                              type: string
                              enum:
                                - data_source_item
                                - file_record
                                - enrichment_cell
                                - participant
                                - connection
                                - profile_read
                                - duplicate_record
                                - manual
                                - legacy_column
                              description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                            observed_at:
                              type: string
                              nullable: true
                              description: When the source saw it (ISO 8601); null for a column with no clock.
                          required:
                            - kind
                            - observed_at
                        description: Per resolved key, where it came from and when.
                    required:
                      - name
                      - picture_url
                      - website
                      - sources
                    description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
                  domain:
                    type: string
                    nullable: true
                    description: "Lowercased apex domain; derived from website when absent; dedup key #3."
                  deal_size:
                    type: number
                    nullable: true
                    description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
                  status:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
                    description: Service-managed (import validation, stoplist); not client-writable.
                  status_reason:
                    type: string
                    nullable: true
                    description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
                  duplicate_of_sid:
                    type: string
                    nullable: true
                    description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
                  duplicate_matched_kind:
                    type: string
                    nullable: true
                    enum:
                      - ln_id
                      - ln_nickname
                      - domain
                    description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
                  tag_sids:
                    type: array
                    nullable: true
                    items:
                      type: string
                  external_refs:
                    anyOf:
                      - type: object
                        additionalProperties:
                          type: string
                      - type: array
                        items: {}
                      - {}
                    description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
                  last_enrich_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                  pipeline_stage_sid:
                    type: string
                    nullable: true
                    description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
                  pipeline_stage_source:
                    type: string
                    nullable: true
                    enum:
                      - derived
                      - manual
                    description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
                required:
                  - sid
                  - team_sid
                  - playtable_sids
                  - data_source_sid
                  - data_source_type
                  - data_source_item_sid
                  - ln_id
                  - ln_nickname
                  - context
                  - domain
                  - deal_size
                  - status
                  - status_reason
                  - duplicate_of_sid
                  - duplicate_matched_kind
                  - tag_sids
                  - external_refs
                  - last_enrich_at
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
                  - pipeline_stage_sid
                  - pipeline_stage_source
              included:
                type: object
                properties:
                  people_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                    description: PeopleCounts aggregate over the company's linked people (legacy leads-summary widget); FK auto-injected (people.company_sid = parent.sid), no other filters pass - see ./people.md.
                  field_values:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: "Trimmed cell projection (value, status, cost, finished_at - no meta.steps) across ALL member playtables; each row carries its playtable_sid. Order: playtable_sid, then field position. Full trace = playtable-field-values get - see ./playtable_field_values.md."
                  last_activities:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: ActivityDomain rows (1:N, limit 20, occurred_at DESC) - see ./activities.md.
                  notes:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: NoteDomain rows (1:N, limit 20, created_at DESC) - see ./notes.md.
                  signals:
                    type: array
                    items:
                      type: object
                      properties:
                        key:
                          type: string
                          enum:
                            - awaiting_reply
                            - opened_not_replied
                            - clicked_not_replied
                            - multi_opened
                            - accepted_not_replied
                            - note_read_not_replied
                            - reacted_not_replied
                            - invited_us
                            - followed_us
                            - lead_messaged_first
                            - unanswered_inbound
                            - draft_pending
                            - escalated_open
                            - task_overdue
                            - went_quiet
                            - reactivated
                            - invite_pending
                            - connection_removed
                            - blocked_us
                            - deleted_message
                            - bounced
                            - bounced_hard
                            - complained
                            - booking_link_sent
                            - objective_reached
                            - viewed_our_profile
                            - visited_our_site
                            - visited_not_replied
                            - visited_key_page
                            - multi_visited
                            - submitted_form
                            - company_visited_our_site
                            - no_people
                            - thin_coverage
                            - nobody_reached
                            - no_engagement
                            - no_reply
                            - exhausted
                            - dormant
                            - dm_missing
                          description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                        since:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: the instant the signal's clock started (our last message, the accept, the reaction...). null when the signal has no clock (draft_pending)."
                        age_days:
                          type: integer
                          nullable: true
                          minimum: 0
                          description: Whole days since `since`, at read time. null when the signal has no clock.
                      required:
                        - key
                        - since
                        - age_days
                    description: "The catalog names the account carries right now, evaluated at read time from the ledger: its own website visit (company_visited_our_site) and the account names over its people (ACCOUNT_PLAYS_RESEARCH.md §4.2: no_people, thin_coverage, nobody_reached, no_engagement, no_reply, exhausted, dormant, dm_missing), each with the instant its clock started and its age in days (both null for a stored fact with no clock). Empty when none holds. Read it before deciding where to top up or whom to re-engage."
                  freshness:
                    type: array
                    items:
                      type: object
                      properties:
                        object_sid:
                          type: string
                          description: "The row: cr_pp_ on a person, cr_co_ on a company."
                        kind:
                          type: string
                          enum:
                            - profile
                            - company
                            - posts
                          description: "profile: the LinkedIn profile (a people-tab column over the person). company: the company page (a people-tab column over a company URL on a person; a companies-tab column on a company). posts: the person's posts."
                        read_at:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: the row's last read of this kind, whoever read (the play, a workflow's Run column step, a column's own run, a hand run). null = never read."
                        play_sid:
                          type: string
                          description: "pt_pl_ the play whose schedule keeps this kind fresh on the row: switched on, daily, its watch names the kind, a column of the row's tab reads the kind, and the row is in its audience (a company is when one of its people is). When several plays cover the row and the kind, the shortest cadence wins."
                        play_name:
                          type: string
                          description: The play's name, for "re-read 2 days ago by Keep data fresh".
                        days:
                          type: integer
                          minimum: 0
                          exclusiveMinimum: true
                          description: The play's cadence for this kind, in days ("every 7 days").
                        next_at:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: read_at plus the cadence, when the schedule reads the row again. null when never read: the next run reads it."
                      required:
                        - object_sid
                        - kind
                        - read_at
                        - play_sid
                        - play_name
                        - days
                        - next_at
                    description: "The company page's read when a watching play keeps it fresh on the company (a companies-tab column reads it, one of the company's people is in the play's audience): the play, its cadence, the last read and the next. Empty when no switched-on daily play covers the company."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Company rows matching the filter scope.
            with_linkedin_count:
              type: integer
              minimum: 0
              description: Rows where ln_id IS NOT NULL OR ln_nickname IS NOT NULL - multi-column OR, no group axis covers it.
            with_domain_count:
              type: integer
              minimum: 0
              description: Rows where domain IS NOT NULL - filterable but not groupable column.
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Rows per CompanyStatusEnum value (3 values, bounded).
                playtable_sids:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Rows per member table (pt_tb_… keys); a company counts once per member table.
                data_source_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Rows per provenance source (ds_sc_… keys).
                signals:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Rows per signal name the account carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many accounts of the scope read no_engagement, exhausted, dm_missing and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the Companies grid, Creator's brief)."
              required:
                - status
                - playtable_sids
                - data_source_sid
                - signals
          required:
            - total_count
            - with_linkedin_count
            - with_domain_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchCreditLedgerEntriesRequest:
      type: object
      description: Request body of `search_credit_ledger_entries`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cl_en_
                  description: Credit ledger entry (receipt) sid (cl_en_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cl_en_
                    description: Credit ledger entry (receipt) sid (cl_en_…).
              additionalProperties: false
              description: Receipt sid(s), cl_en_ prefix (prefix-validated).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: Per-table spend scope (pt_tb_…).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
              additionalProperties: false
              description: "Residual inside scope: people | company."
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: cr_pp_… / cr_co_… (mixed prefixes - not prefix-pinned); cell drill-down with playtable_field_sid.
            playtable_field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: Per-field spend scope (pt_fd_…).
            run_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_rn_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rn_
                is_null:
                  type: boolean
              additionalProperties: false
              description: What a run cost (pt_rn_…); is_null:true = non-run spend (empty in v1 - the cell-waterfall writer always carries a run).
            tool_sid:
              type: object
              properties:
                eq:
                  type: string
                  maxLength: 64
                in:
                  type: array
                  items:
                    type: string
                    maxLength: 64
              additionalProperties: false
              description: Spend through one gtm-api tool (external sid, opaque).
            created_by_actor_sid:
              type: object
              properties:
                eq:
                  type: string
              additionalProperties: false
              description: '"What did this person spend" - projected from created_by.actor_sid.'
            idempotency_key:
              type: object
              properties:
                eq:
                  type: string
                  maxLength: 128
              additionalProperties: false
              description: "Support/debug: locate one exact charge."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range - day windows; combine bounds in one object. Ignored on metrics - period owns the window.
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - field
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - cost
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchCreditLedgerEntriesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Receipt sid (cl_en_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  playtable_sid:
                    type: string
                    nullable: true
                    description: pt_tb_… table context - see ./playtables.md; audit ref, may dangle after table delete.
                  object_type:
                    type: string
                    nullable: true
                    enum:
                      - people
                      - company
                    description: "Kind of the enriched row: people | company; null when the receipt has no cell context."
                  object_sid:
                    type: string
                    nullable: true
                    description: cr_pp_… / cr_co_… enriched row (polymorphic by object_type) - audit ref, may dangle.
                  playtable_field_sid:
                    type: string
                    nullable: true
                    description: pt_fd_… field whose waterfall spent - see ./playtable_fields.md; audit ref, may dangle.
                  run_sid:
                    type: string
                    nullable: true
                    description: pt_rn_… run that dispatched the step; outlives the run's 90-day purge as an opaque audit ref.
                  step_index:
                    type: integer
                    nullable: true
                    minimum: 0
                    description: Position in the materialized waterfall; matches the cell's meta.steps[step_index].
                  tool_sid:
                    type: string
                    description: gtm-api tool executed (external registry sid, max 64).
                  provider_sid:
                    type: string
                    nullable: true
                    description: Serving provider when gtm-api resolved one; display-only - presets hide provider chains.
                  cost:
                    type: number
                    minimum: 0
                    exclusiveMinimum: true
                    description: Credits this step charged (decimal(12,4), > 0 - zero-cost steps never receipt).
                  idempotency_key:
                    type: string
                    description: Per-step dedup axis (max 128, DB UNIQUE) shared with the gtm-api call and the tool-result callback.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Spend attribution - the run initiator on whose behalf the worker spent (denormalized from the run at record time), NOT the row writer.
                  created_at:
                    type: string
                    description: ISO 8601 UTC - the receipt clock and metrics period column.
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - object_type
                  - object_sid
                  - playtable_field_sid
                  - run_sid
                  - step_index
                  - tool_sid
                  - provider_sid
                  - cost
                  - idempotency_key
                  - created_by
                  - created_at
              included:
                type: object
                properties:
                  field:
                    type: object
                    properties:
                      sid:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      category:
                        type: string
                      type:
                        type: string
                    required:
                      - sid
                      - name
                      - slug
                      - category
                      - type
                    description: "1:1 field whose waterfall spent (include[]=field): name/slug/preset for receipt display; hydrates soft-deleted fields too (audit context); absent when the field row is gone."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Receipts (paid calls) matching the filter - full filter scope, not the page.
            groups:
              type: object
              properties:
                playtable_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {pt_tb_ sid: call count} - which table is spending."
                playtable_field_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {pt_fd_ sid: call count} - call concentration by field."
                tool_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {tool_sid: call count} - calls through each gtm-api tool."
                created_date:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {'YYYY-MM-DD': call count} - calls per UTC day (≤ 366 values under 12-month retention)."
              required:
                - playtable_sid
                - playtable_field_sid
                - tool_sid
                - created_date
              description: One axis per CreditLedgerEntryGroupableFieldsEnum value (§4.17). Values are CALL COUNTS - credit sums live in the metrics tool. PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchDataSourceItemsRequest:
      type: object
      description: Request body of `search_data_source_items`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_it_
                  description: Item sid (ds_it_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_it_
                    description: Item sid (ds_it_…).
              additionalProperties: false
              description: Prefix-validated ds_it_ sid(s) - the point-lookup path (no get tool); resolves people.data_source_item_sid provenance backlinks.
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
              additionalProperties: false
              description: The primary review scope - funnel drill-downs always pass the source.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - pending
                    - promoted
                    - duplicate
                    - stoplisted
                    - disqualified
                    - failed
                ne:
                  type: string
                  enum:
                    - pending
                    - promoted
                    - duplicate
                    - stoplisted
                    - disqualified
                    - failed
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - pending
                      - promoted
                      - duplicate
                      - stoplisted
                      - disqualified
                      - failed
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - pending
                      - promoted
                      - duplicate
                      - stoplisted
                      - disqualified
                      - failed
              additionalProperties: false
              description: Promotion outcome(s) - in:["failed","duplicate","stoplisted","disqualified"] = "rows that did not make it".
            created_object_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                is_null:
                  type: boolean
              additionalProperties: false
              description: Provenance backlink (cr_pp_ or cr_co_ per the source object type); is_null:true = rows that produced nothing.
            q:
              type: string
              maxLength: 128
              description: MySQL LIKE (infix) over the raw payload JSON - find one record by any fragment (name, email). Requires data_source_sid (eq or in) in the same filter, else 422 - payload search is per-source.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Ingestion window; ISO 8601 range - combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Terminal-transition window ("failures in the last hour").
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - data_source
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - updated_at
                - row_number
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchDataSourceItemsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Item sid (ds_it_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  data_source_sid:
                    type: string
                    description: ds_sc_… owning source - see ./data_sources.md; set at birth, never re-validated.
                  row_number:
                    type: integer
                    nullable: true
                    minimum: 1
                    description: 1-based CSV data-row position (type=csv sources); null for the search kinds and for webhook.
                  payload:
                    anyOf:
                      - type: object
                        additionalProperties: {}
                      - type: array
                        items:
                          type: string
                          nullable: true
                    description: "Raw external record as ingested, never mutated (legacy raw_data). An object for every kind: the collector parser record for a search source, the CSV row keyed by its own header for csv, the selected slice of the body for webhook. Only csv rows staged before 2026-08-04 are positional string arrays."
                  status:
                    type: string
                    enum:
                      - pending
                      - promoted
                      - duplicate
                      - stoplisted
                      - disqualified
                      - failed
                    description: Promotion outcome - service-managed, never client-writable.
                  status_reason:
                    type: string
                    nullable: true
                    description: "Human-readable outcome detail (max 2048): failure message or matched stoplist entry; null for pending and clean promoted rows (legacy error_reason)."
                  created_object_sid:
                    type: string
                    nullable: true
                    description: Created/updated object on promoted, matched object on duplicate - the prefix follows the source object type (cr_pp_ people, cr_co_ companies). Write-once at resolve; may dangle after the object is deleted.
                  already_in_playtable_sid:
                    type: string
                    nullable: true
                    description: Duplicate people rows only - pt_tb_… the person's membership at match time; snapshot, never re-validated.
                  duplicate_action:
                    type: string
                    nullable: true
                    enum:
                      - skipped
                      - moved
                      - membership_added
                      - merged
                      - disqualified
                    description: Duplicate rows only - what the duplicate policy did; null otherwise (incl. company already a member).
                  created_at:
                    type: string
                    description: ISO 8601 UTC - ingestion time (the "collected" period column).
                  updated_at:
                    type: string
                    description: ISO 8601 UTC - terminal transition time (the funnel period column read by data-sources metrics).
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - set only by the source cascade delete; null = live. Terminal rows hard-purge 90 days after updated_at.
                required:
                  - sid
                  - team_sid
                  - data_source_sid
                  - row_number
                  - payload
                  - status
                  - status_reason
                  - created_object_sid
                  - already_in_playtable_sid
                  - duplicate_action
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  data_source:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: DataSourceDomain row (ds_sc_…) - the owning source - see ./data_sources.md; present when requested.
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Rows matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {value: count} per DataSourceItemStatusEnum value present in scope - the import funnel."
                duplicate_action:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "The duplicate rows by what the policy did (DataSourceItemDuplicateAction → count), 2026-10-28: the rows keep status duplicate, so read the people moved into the table (moved) as imported and the rest as duplicates still standing. Empty when there are none."
                already_in_playtable_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "The duplicate people the policy left where they were (status duplicate, duplicate_action skipped), by the table they are in (pt_tb_… → count): what move_data_source_duplicates would move (2026-10-28). Empty when there are none."
              required:
                - status
              description: The distribution axes (§4.17); PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchDataSourcesRequest:
      type: object
      description: Request body of `search_data_sources`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                  description: Data source sid (ds_sc_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                    description: Data source sid (ds_sc_…).
              additionalProperties: false
              description: Prefix-validated ds_sc_ sid(s).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Sources feeding table X; is_null:true = orphaned by playtable deletion.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ai_search
                    - sender_search
                    - post_engagement
                    - find_people
                    - csv
                    - webhook
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ai_search
                      - sender_search
                      - post_engagement
                      - find_people
                      - csv
                      - webhook
              additionalProperties: false
              description: "The kind tabs of the sources page: ai_search | sender_search | post_engagement | find_people | csv | webhook."
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - people
                      - company
              additionalProperties: false
              description: "What the source brings: people | company."
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Sources run by a given sender profile (ub_sp_…); is_null:true = everything the platform pool or a file feeds.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - completed
                    - failed
                ne:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - completed
                    - failed
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - completed
                      - failed
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - completed
                      - failed
              additionalProperties: false
            q:
              type: string
              maxLength: 128
              description: Free text over name only (MySQL LIKE, infix).
            next_collect_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Due/overdue scans; ISO 8601. is_null:true = clock-less (csv, webhook, and a bus-served sender search).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - playtable
              - sender_profile
              - data_source_items_counts
              - indexed_counts
              - csv_preview
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - name
                - next_collect_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchDataSourcesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                    nullable: true
                    description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
                  name:
                    type: string
                    description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
                  type:
                    type: string
                    enum:
                      - ai_search
                      - sender_search
                      - post_engagement
                      - find_people
                      - csv
                      - webhook
                    description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                    description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
                  sender_profile_sid:
                    type: string
                    nullable: true
                    description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
                  ingest_key:
                    type: string
                    nullable: true
                    description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
                  payload:
                    anyOf:
                      - type: object
                        properties:
                          platform:
                            type: string
                            enum:
                              - linkedin
                              - sales_navigator
                              - recruiter
                            description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                          surface:
                            type: string
                            enum:
                              - search
                              - saved_search
                              - list
                              - post
                              - my_network
                              - messenger
                            description: "ai_search (link mode) and sender_search: what kind of list the link is."
                          repeat:
                            type: string
                            nullable: true
                            enum:
                              - hourly
                              - daily
                              - weekly
                              - monthly
                            description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                          mode:
                            type: string
                            enum:
                              - create
                              - update
                            description: "csv: what the import does with its rows."
                          target:
                            type: string
                            enum:
                              - post
                              - person
                              - company
                            description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                          window:
                            anyOf:
                              - type: object
                                properties:
                                  days:
                                    anyOf:
                                      - type: number
                                        enum:
                                          - 7
                                      - type: number
                                        enum:
                                          - 30
                                      - type: number
                                        enum:
                                          - 90
                                required:
                                  - days
                                additionalProperties: false
                              - type: object
                                properties:
                                  since:
                                    type: string
                                    pattern: ^\d{4}-\d{2}-\d{2}$
                                required:
                                  - since
                                additionalProperties: false
                            description: "post_engagement, a person or a company: the window the posts are read from."
                          relevance:
                            type: object
                            properties:
                              prompt:
                                type: string
                            required:
                              - prompt
                            description: "post_engagement: the AI post filter; absent = every post is walked."
                          collect:
                            type: object
                            properties:
                              reactions:
                                type: boolean
                              comments:
                                type: boolean
                              reposts:
                                type: boolean
                            additionalProperties: false
                            description: "post_engagement: the feeds the walk collects."
                          posts:
                            type: array
                            items:
                              type: object
                              properties:
                                urn:
                                  type: string
                                title:
                                  type: string
                                published_at:
                                  type: string
                                  nullable: true
                                verdict:
                                  type: string
                                  enum:
                                    - match
                                    - skip
                                verdict_reason:
                                  type: string
                              required:
                                - urn
                            description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                      - type: array
                        items: {}
                    description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
                  field_mapping:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        source:
                          type: string
                          minLength: 1
                          maxLength: 512
                          description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                        target_kind:
                          type: string
                          enum:
                            - people_attribute
                            - company_attribute
                            - field_slug
                          description: people_attribute | company_attribute | field_slug.
                        target:
                          type: string
                          minLength: 1
                          maxLength: 255
                          description: Attribute key (people / company) or a playtable field slug in the target table.
                        name:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 255
                          description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                      required:
                        - source
                        - target_kind
                        - target
                    description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
                  tag_sids:
                    type: array
                    nullable: true
                    items:
                      type: string
                    description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
                  qualify:
                    type: object
                    nullable: true
                    properties:
                      "on":
                        type: boolean
                        description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                      criterion:
                        type: string
                        nullable: true
                        minLength: 1
                        maxLength: 2000
                        description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                    required:
                      - "on"
                      - criterion
                    additionalProperties: false
                    description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
                  on_duplicate:
                    type: string
                    enum:
                      - skip
                      - move
                    description: Duplicate-person policy; default 'skip'.
                  add_tags_to_duplicate:
                    type: boolean
                    description: Merge tag_sids onto matched duplicates; default false.
                  status:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - completed
                      - failed
                  status_reason:
                    type: string
                    nullable: true
                    description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
                  next_collect_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - name
                  - type
                  - object_type
                  - sender_profile_sid
                  - ingest_key
                  - payload
                  - field_mapping
                  - tag_sids
                  - qualify
                  - on_duplicate
                  - add_tags_to_duplicate
                  - status
                  - status_reason
                  - next_collect_at
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  playtable:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: PlaytableDomain (1:1 via playtable_sid) - see ./playtables.md.
                  sender_profile:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: SenderProfileDomain (1:1 via sender_profile_sid), the sender profile that collects a sender search or a post engagement; its linkedin_has_sn / linkedin_recruiter_status say which links it can open - see ./sender_profiles.md.
                  data_source_items_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: "The import funnel: pending / promoted / duplicate / stoplisted / failed."
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                    description: "DataSourceItemCounts computed over { data_source_sid: parent.sid } - the per-source import funnel at full scope (§4.17 parent-include) - see ./data_source_items.md."
                  indexed_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                    description: How many of the source's objects are already VISIBLE in the People / Companies grids (the read-plane twin of the funnel's `promoted`, which counts MySQL truth the moment an item lands). Quote this one, not `promoted`, next to a link into the grid.
                  csv_preview:
                    type: object
                    nullable: true
                    properties:
                      headers:
                        type: array
                        items:
                          type: string
                      rows:
                        type: array
                        items:
                          type: array
                          items:
                            type: string
                            nullable: true
                      total_rows:
                        type: integer
                        minimum: 0
                    required:
                      - headers
                      - rows
                      - total_rows
                    description: "type=csv only: header row + the first 5 data rows + total_rows, replayed from the stored file so a draft's mapping step can resume. null for every other kind and for an unreadable file. Request it on get, not as list hydration."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Source rows matching the filter scope.
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                object_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
              required:
                - status
                - type
                - object_type
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchNotesRequest:
      type: object
      description: Request body of `search_notes`.
      properties:
        filter:
          type: object
          properties:
            q:
              type: string
              maxLength: 128
              description: Free text over note bodies (MySQL FULLTEXT over body).
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_nt_
                  description: Note sid (cr_nt_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_nt_
                    description: Note sid (cr_nt_…).
              additionalProperties: false
              description: Note sid(s), cr_nt_ prefix - also the point-lookup path (no get tool).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
                    - workflow
              additionalProperties: false
              description: "Object kind: person | company | workflow."
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: The annotated object(s), cr_pp_ / cr_co_ / wf_wf_ - the notes-widget scope, or a workflow's stickers.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live notes)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - person
              - company
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchNotesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Note sid (cr_nt_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  object_type:
                    type: string
                    enum:
                      - person
                      - company
                      - workflow
                    description: "Kind of the annotated object: person | company | workflow (a sticker on its canvas). Fixed at create - a note is never re-homed."
                  object_sid:
                    type: string
                    description: The annotated person (cr_pp_…), company (cr_co_…) or workflow (wf_wf_…); prefix matches object_type.
                  body:
                    type: string
                    description: Plain-text note body, rendered as-is; FULLTEXT-indexed for filter.q. 1..65535 chars on a person or company; a sticker may be empty.
                  step_id:
                    type: integer
                    nullable: true
                    description: "A sticker only: the workflow step it sits beside; null = the workflow as a whole (and always null on a person or company note)."
                  position:
                    type: object
                    nullable: true
                    properties:
                      x:
                        type: integer
                        minimum: -50000
                        maximum: 50000
                      "y":
                        type: integer
                        minimum: -50000
                        maximum: 50000
                    required:
                      - x
                      - "y"
                    additionalProperties: false
                    description: "A sticker only: where a person dragged it, relative to its step; null = the canvas places it beside its step."
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that authored the note (AccessIdentityValue); shown for accountability.
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that soft-deleted the note (tool call or parent cascade); null while live.
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC; bumped by body edits.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete).
                required:
                  - sid
                  - team_sid
                  - object_type
                  - object_sid
                  - body
                  - step_id
                  - position
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  person:
                    type: object
                    additionalProperties: {}
                    description: Annotated person row (PeopleDomain - entities/people.md). Present on object_type=person rows when requested and found.
                  company:
                    type: object
                    additionalProperties: {}
                    description: Annotated company row (CompanyDomain - entities/companies.md). Present on object_type=company rows when requested and found.
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Notes matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                object_type:
                  anyOf:
                    - type: object
                      properties:
                        person:
                          type: integer
                          minimum: 0
                        company:
                          type: integer
                          minimum: 0
                        workflow:
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: Note distribution across the object kinds; absent key = zero.
              required:
                - object_type
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPeopleRequest:
      type: object
      description: Request body of `search_people`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
              additionalProperties: false
              description: Prefix-validated cr_pp_ sid(s).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every table view passes { eq: <table> }."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The stage's funnel bucket (one of seven), expanded on the server into the team's person stage sids of those categories: ask by name, never resolve stages. eq approaching = we reached out, nothing came back; in [engaging, positive] = something came back."
            company_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                is_null:
                  type: boolean
              additionalProperties: false
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            linkedin_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                ne:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
              additionalProperties: false
            email_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                is_null:
                  type: boolean
              additionalProperties: false
            phone_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                is_null:
                  type: boolean
              additionalProperties: false
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap semantics (any of) - in matches rows whose tag array overlaps the list; nin answers the complement, untagged rows included.
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the person, all must hold. The server expands a name into its keyword and clock range: never compose them. A bare entry takes the catalog default age, age_days moves it. A thread-only name is a 422 (ask search_conversations)."
            ln_member_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact identifier.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw profile URN.
            sn_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw Sales Navigator URN.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact vanity slug (lowercased); use q for fuzzy.
            work_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: is_null:true = coverage gap.
            personal_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
            q:
              type: string
              maxLength: 128
              description: Free text (ES people index) over the resolved name and company name, the emails and the slug. Filter a company by company_sid.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - company
              - field_values
              - workflow_records
              - last_activities
              - notes
              - engagement
              - engagement_by_sender
              - signals
              - freshness
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              anyOf:
                - type: string
                  enum:
                    - row_order
                    - created_at
                    - updated_at
                    - full_name
                    - company_name
                - type: string
                  pattern: ^fields\.[a-z][a-z0-9_]{0,63}$
                  description: Custom column of the pinned playtable, by slug.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: Default asc for row_order, desc otherwise.
          required:
            - field
          description: One sort column with its direction; default row_order asc, the grid row order (a per-team arrival sequence, never a job title).
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
        filter_ast:
          description: "The view filter AST, ANDed with filter: typed leaves (attributes, record.<slug> cells, journeys), a signals leaf (names the person carries) and company_signals (people whose ACCOUNT carries any of the account names; ne / nin = none; max 10000 accounts)."
        sids_only:
          type: boolean
          description: "Answer the matching sids only (the grid's ids-only model): items carry {sid} and nothing else."
        semantic:
          type: object
          properties:
            field:
              type: string
              minLength: 8
              maxLength: 96
              pattern: ^record\.
              description: The semantic column, record.<slug>, whose value vectors are searched.
            query:
              type: string
              minLength: 1
              maxLength: 2048
              description: Natural-language query embedded and matched against the column.
            k:
              type: integer
              minimum: 1
              maximum: 500
              description: Nearest neighbours to keep before the filter applies. Default 100.
            min_score:
              type: number
              minimum: 0
              maximum: 1
              description: "The match floor on the score the rows come back with (0..1, cosine mapped as (1 + cos) / 2): a row below it is out, not last. Default: no floor, the k nearest stay."
          required:
            - field
            - query
          description: Semantic search over one embedded column (research §Filterable, the I5 engine); the result order is similarity.
    SearchPeopleResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                    description: pt_tb_… - the SINGLE playtable membership; service-managed, changes only via move (create on_duplicate:move / run type move).
                  data_source_sid:
                    type: string
                    nullable: true
                  data_source_item_sid:
                    type: string
                    nullable: true
                  company_sid:
                    type: string
                    nullable: true
                  context:
                    type: object
                    nullable: true
                    properties:
                      name:
                        type: string
                        nullable: true
                      first_name:
                        type: string
                        nullable: true
                        description: The source's own first name when it gave one, else the first word of name.
                      picture_url:
                        type: string
                        nullable: true
                        description: A permanent copy over a wire link, the wire link that lasts longest, an expired one counts as none.
                      role:
                        type: string
                        nullable: true
                        description: The title at the company (the Sales Navigator wire's position, the enrichment's).
                      headline:
                        type: string
                        nullable: true
                        description: The profile line (the regular and Recruiter wires, the inbox participant, the enrichment).
                      company:
                        type: object
                        nullable: true
                        properties:
                          sid:
                            type: string
                            nullable: true
                            description: cr_co_… when the person is linked to an account (the account's own resolved context follows); null = a name that is not an account, an import whose company column resolved to none.
                          name:
                            type: string
                            nullable: true
                          domain:
                            type: string
                            nullable: true
                          picture_url:
                            type: string
                            nullable: true
                          ln_id:
                            type: string
                            nullable: true
                            description: "The company's LinkedIn id: the linked account's own, else the person's company id as a source or an edit gave it."
                        required:
                          - sid
                          - name
                          - domain
                          - picture_url
                          - ln_id
                      sources:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            kind:
                              type: string
                              enum:
                                - data_source_item
                                - file_record
                                - enrichment_cell
                                - participant
                                - connection
                                - profile_read
                                - duplicate_record
                                - manual
                                - legacy_column
                              description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                            observed_at:
                              type: string
                              nullable: true
                              description: When the source saw it (ISO 8601); null for a column with no clock.
                          required:
                            - kind
                            - observed_at
                        description: Per resolved key, where it came from and when.
                    required:
                      - name
                      - first_name
                      - picture_url
                      - role
                      - headline
                      - company
                      - sources
                    description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, first name, picture, role, headline and company a surface or a model shows next to the row, resolved at read from the observations ledger: a manual word until reset, then the newest LinkedIn-derived observation, then any other. The only place these words are: the row keeps identifiers (phase E, 2026-10-22). Null only on an event payload."
                  ln_member_id:
                    type: string
                    nullable: true
                  ln_id:
                    type: string
                    nullable: true
                  sn_id:
                    type: string
                    nullable: true
                  recruiter_id:
                    type: string
                    nullable: true
                  work_email:
                    type: string
                    nullable: true
                  personal_email:
                    type: string
                    nullable: true
                  work_phone_number:
                    type: string
                    nullable: true
                  personal_phone_number:
                    type: string
                    nullable: true
                  status:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
                    description: Service-managed row validity (import validation, stoplist, duplicate detection) - not client-writable.
                  duplicate_of_sid:
                    type: string
                    nullable: true
                    description: "While status is duplicate: the PRIMARY row (cr_pp_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_person_primary. Null otherwise."
                  duplicate_matched_kind:
                    type: string
                    nullable: true
                    enum:
                      - ln_member_id
                      - ln_id
                      - sn_id
                      - recruiter_id
                      - email
                      - ln_nickname
                      - phone
                    description: "While status is duplicate: the identifier the check matched on. Null otherwise."
                  linkedin_status:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
                  email_status:
                    type: string
                    nullable: true
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                  phone_status:
                    type: string
                    nullable: true
                    enum:
                      - need_search
                      - no_data
                      - ok
                  tag_sids:
                    type: array
                    nullable: true
                    items:
                      type: string
                  external_refs:
                    anyOf:
                      - type: object
                        additionalProperties:
                          type: string
                      - type: array
                        items: {}
                      - {}
                    description: Free-form CRM sync map (hubspot_contact_id, …) - keys integration-defined, round-tripped as-is; PHP empty map serialises as [].
                  last_enrich_at:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                  pipeline_stage_sid:
                    type: string
                    nullable: true
                    description: The funnel stage the person is in (cr_ps_...), derived from activity or moved by hand (pipeline_stages.md); null = no stage.
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - data_source_sid
                  - data_source_item_sid
                  - company_sid
                  - context
                  - ln_member_id
                  - ln_id
                  - sn_id
                  - recruiter_id
                  - work_email
                  - personal_email
                  - work_phone_number
                  - personal_phone_number
                  - status
                  - duplicate_of_sid
                  - duplicate_matched_kind
                  - linkedin_status
                  - email_status
                  - phone_status
                  - tag_sids
                  - external_refs
                  - last_enrich_at
                  - created_at
                  - updated_at
                  - deleted_at
                  - pipeline_stage_sid
              included:
                type: object
                properties:
                  company:
                    type: object
                    nullable: true
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: CompanyDomain (N:1 via company_sid) - see ./companies.md.
                  field_values:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: "PlaytableFieldValueDomain rows - ALL live cells of the person's playtable (the table-row hydration: renders the custom columns), ordered by field position - see ./playtable_field_values.md."
                  workflow_records:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: WorkflowRecordDomain rows in a NON-TERMINAL status only (active memberships; 1:N, limit 20, created_at DESC) - see ./workflow_records.md.
                  last_activities:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: ActivityDomain rows (1:N, limit 20, occurred_at DESC) - the ingested timeline - see ./activities.md.
                  notes:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: NoteDomain rows (1:N, limit 20, created_at DESC) - see ./notes.md.
                  engagement:
                    type: object
                    properties: {}
                    description: "The person's engagement counters and dates folded over EVERY fact of the activities ledger (the search document's `engagement` keys, D43: messages sent and received per channel, opens, clicks, invitations sent / accepted / withdrawn, visits, likes, comments, endorsements, bounces, unsubscribes, replies, touches, the last touch and last message with their channel and direction). Every key present: 0 / null until a fact moves it. What the LinkedIn channel and Email channel widget cells draw; shares one read with engagement_by_sender."
                  engagement_by_sender:
                    type: array
                    items:
                      type: object
                      properties:
                        sender_profile_sid:
                          type: string
                      required:
                        - sender_profile_sid
                    description: "The same counters per sender profile (ub_sp_ sid): the facts whose payload names it. Empty when no fact of the person names a sender profile."
                  signals:
                    type: array
                    items:
                      type: object
                      properties:
                        key:
                          type: string
                          enum:
                            - awaiting_reply
                            - opened_not_replied
                            - clicked_not_replied
                            - multi_opened
                            - accepted_not_replied
                            - note_read_not_replied
                            - reacted_not_replied
                            - invited_us
                            - followed_us
                            - lead_messaged_first
                            - unanswered_inbound
                            - draft_pending
                            - escalated_open
                            - task_overdue
                            - went_quiet
                            - reactivated
                            - invite_pending
                            - connection_removed
                            - blocked_us
                            - deleted_message
                            - bounced
                            - bounced_hard
                            - complained
                            - booking_link_sent
                            - objective_reached
                            - viewed_our_profile
                            - visited_our_site
                            - visited_not_replied
                            - visited_key_page
                            - multi_visited
                            - submitted_form
                            - company_visited_our_site
                            - no_people
                            - thin_coverage
                            - nobody_reached
                            - no_engagement
                            - no_reply
                            - exhausted
                            - dormant
                            - dm_missing
                          description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                        since:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: the instant the signal's clock started (our last message, the accept, the reaction...). null when the signal has no clock (draft_pending)."
                        age_days:
                          type: integer
                          nullable: true
                          minimum: 0
                          description: Whole days since `since`, at read time. null when the signal has no clock.
                      required:
                        - key
                        - since
                        - age_days
                    description: "The catalog names the person carries right now (SIGNALS_RESEARCH.md §5.3: evaluated from the engagement counters across every sender profile), each with the instant its clock started and its age in days. Empty when none holds. Ask it before drafting or deciding a next step; the thread-level names (drafts, escalations, tasks, reactions) are get_conversation's."
                  freshness:
                    type: array
                    items:
                      type: object
                      properties:
                        object_sid:
                          type: string
                          description: "The row: cr_pp_ on a person, cr_co_ on a company."
                        kind:
                          type: string
                          enum:
                            - profile
                            - company
                            - posts
                          description: "profile: the LinkedIn profile (a people-tab column over the person). company: the company page (a people-tab column over a company URL on a person; a companies-tab column on a company). posts: the person's posts."
                        read_at:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: the row's last read of this kind, whoever read (the play, a workflow's Run column step, a column's own run, a hand run). null = never read."
                        play_sid:
                          type: string
                          description: "pt_pl_ the play whose schedule keeps this kind fresh on the row: switched on, daily, its watch names the kind, a column of the row's tab reads the kind, and the row is in its audience (a company is when one of its people is). When several plays cover the row and the kind, the shortest cadence wins."
                        play_name:
                          type: string
                          description: The play's name, for "re-read 2 days ago by Keep data fresh".
                        days:
                          type: integer
                          minimum: 0
                          exclusiveMinimum: true
                          description: The play's cadence for this kind, in days ("every 7 days").
                        next_at:
                          type: string
                          nullable: true
                          description: "ISO 8601 UTC: read_at plus the cadence, when the schedule reads the row again. null when never read: the next run reads it."
                      required:
                        - object_sid
                        - kind
                        - read_at
                        - play_sid
                        - play_name
                        - days
                        - next_at
                    description: "Per read kind a watching play keeps fresh on the person (the LinkedIn profile, the company page a people-tab column reads, the posts): the play, its cadence, the last read and the next. One entry per kind at most; empty when no switched-on daily play covers the person. How old a profile read is, and whether the table re-reads it on its own."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: People rows matching the filter scope.
            with_email_count:
              type: integer
              minimum: 0
              description: work_email IS NOT NULL OR personal_email IS NOT NULL (multi-column OR).
            with_phone_count:
              type: integer
              minimum: 0
              description: work_phone_number IS NOT NULL OR personal_phone_number IS NOT NULL (multi-column OR).
            with_linkedin_count:
              type: integer
              minimum: 0
              description: "Any LinkedIn identity axis present: ln_member_id, ln_id, sn_id, recruiter_id or ln_nickname (multi-column OR)."
            with_company_count:
              type: integer
              minimum: 0
              description: company_sid IS NOT NULL (filterable but not groupable column).
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                linkedin_status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                email_status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                phone_status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                playtable_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                data_source_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                signals:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: "Rows per signal name the person carries at the catalog's default threshold, present names only (a filters aggregation, not a terms axis): how many people of the scope read awaiting_reply, went_quiet, dormant and the rest, in one page_size:0 call (ACCOUNT_PLAYS_RESEARCH.md §4.4: the chips over the People grid)."
              required:
                - status
                - linkedin_status
                - email_status
                - phone_status
                - playtable_sid
                - data_source_sid
                - signals
          required:
            - total_count
            - with_email_count
            - with_phone_count
            - with_linkedin_count
            - with_company_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPipelineStagesRequest:
      type: object
      description: Request body of `search_pipeline_stages`.
      properties:
        filter:
          type: object
          properties:
            q:
              type: string
              maxLength: 128
              description: Free text over name (MySQL LIKE, prefix/infix - a small per-team list, no FULLTEXT).
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ps_
                  description: Pipeline stage sid (cr_ps_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ps_
                    description: Pipeline stage sid (cr_ps_…).
              additionalProperties: false
              description: Prefix-validated cr_ps_ sid(s) - also the point-lookup path (no get tool).
            object:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - person
                    - company
              additionalProperties: false
              description: "Which pipeline. Pin it on nearly every call: the person and company lists are separate and reading both at once is almost never what was asked."
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: Funnel bucket - category.in:['positive','nurture'] slices the winnable end of the funnel; category.eq:'approaching' the stages where we reached out and nothing came back.
            key:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Stable system anchor. key.eq resolves one system stage to its sid; is_null:true = the custom stages only.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact label lookup (resolve a stage name the user said into a sid); substring matching goes through q.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live stages)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - order
                - name
                - created_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPipelineStagesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Pipeline stage sid (cr_ps_…) - the value people.pipeline_stage_sid / companies.pipeline_stage_sid store.
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  object:
                    type: string
                    enum:
                      - person
                      - company
                    description: "Which pipeline this stage belongs to: person (leads) | company (accounts). Immutable after create."
                  name:
                    type: string
                    description: Stage label (1..255), unique per (team, object) among live rows, case-insensitively.
                  category:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
                    description: "Funnel bucket, one of seven: the grouping of the company card and the grid, the chip colour, the funnel analytics and the company derivation (positive > engaging > approaching > nurture > negative > cold; a person on a disqualified stage is not an active member of the account). negative = a real no (Not interested); disqualified = not a target, filtered out (Wrong Decision Maker, Disqualified). Locked on a system stage (key != null)."
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that created the stage (AccessIdentityValue); the seeded system stages carry the system identity.
                  key:
                    type: string
                    nullable: true
                    description: "Stable snake_case anchor on SYSTEM stages ('new_contact', 'company_opportunity', …), the target the auto-transition engine resolves; null = a custom stage. key != null is what makes a stage system: locked category, non-deletable. Read-only."
                  order:
                    type: integer
                    nullable: true
                    description: Position within its (team, object) pipeline, contiguous 1..N, and the forward-only rank for a person (a target stage is only auto-entered when its order >= the current one). 0 = pulled out of the ordering (a soft-deleted row).
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC; bumped by rename / recategorize / reorder.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete).
                required:
                  - sid
                  - team_sid
                  - object
                  - name
                  - category
                  - created_by
                  - key
                  - order
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Stages matching the filter (full filter scope, not the page).
            groups:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Always empty - the stage list has no bounded group axis (research §Groupable fields). PHP serialises an empty map as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaysRequest:
      type: object
      description: Request body of `search_plays`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_pl_
                  description: Play sid (pt_pl_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
                    description: Play sid (pt_pl_…).
              additionalProperties: false
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "The Plays tab of a table: every table's list passes { eq: <pt_tb_> }."
            catalog_key:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - keep_fresh
                    - congratulate
                    - on_job_change
                    - engage_posts
                    - on_website_visit
                    - find_people_empty
                    - top_up_thin
                    - top_up_silent
                    - top_up_no_reply
                    - top_up_exhausted
                    - find_decision_maker
                    - reengage_dormant
                    - reach_untouched
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - keep_fresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
                      - find_people_empty
                      - top_up_thin
                      - top_up_silent
                      - top_up_no_reply
                      - top_up_exhausted
                      - find_decision_maker
                      - reengage_dormant
                      - reach_untouched
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The playbook's rows ({ is_null: false }) against the plays saved from a view ({ is_null: true })."
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - people
                      - company
              additionalProperties: false
            action_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - find_people
                    - add_to_workflow
                    - refresh
                    - congratulate
                    - on_job_change
                    - engage_posts
                    - on_website_visit
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - find_people
                      - add_to_workflow
                      - refresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
              additionalProperties: false
            cadence:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - manual
                    - daily
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - manual
                      - daily
              additionalProperties: false
            enabled:
              type: object
              properties:
                eq:
                  type: boolean
              additionalProperties: false
              description: "The daily plays that run by themselves: { eq: true }."
            q:
              type: string
              maxLength: 128
              description: Free-text LIKE over name.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live plays)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - name
                - last_run_at
                - next_run_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaysResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Play sid (pt_pl_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…).
                  playtable_sid:
                    type: string
                    description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
                  catalog_key:
                    type: string
                    nullable: true
                    enum:
                      - keep_fresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
                      - find_people_empty
                      - top_up_thin
                      - top_up_silent
                      - top_up_no_reply
                      - top_up_exhausted
                      - find_decision_maker
                      - reengage_dormant
                      - reach_untouched
                    description: The playbook entry the row was born from; null = a play saved from a view's filter.
                  name:
                    type: string
                    description: The play's name, 1..255.
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                    description: "What the audience selects: people, or company (accounts)."
                  action_type:
                    type: string
                    enum:
                      - find_people
                      - add_to_workflow
                      - refresh
                      - congratulate
                      - on_job_change
                      - engage_posts
                      - on_website_visit
                    description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
                  action:
                    anyOf:
                      - type: object
                        properties:
                          prompt:
                            type: string
                            nullable: true
                            description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                          per_company_limit:
                            type: integer
                            nullable: true
                            description: People taken per account, 1..25; null = the whole first page.
                          data_source_sid:
                            type: string
                            nullable: true
                            description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                        required:
                          - prompt
                          - per_company_limit
                          - data_source_sid
                      - type: object
                        properties:
                          workflow_sid:
                            type: string
                            nullable: true
                            description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                          workflow_source_sid:
                            type: string
                            nullable: true
                            description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                        required:
                          - workflow_sid
                          - workflow_source_sid
                      - type: object
                        properties:
                          moments:
                            type: object
                            properties:
                              birthday:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                              work_anniversary:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                              job_change:
                                type: object
                                properties:
                                  "on":
                                    type: boolean
                                    description: The moment's switch.
                                  do:
                                    type: string
                                    enum:
                                      - send_message
                                      - add_to_workflow
                                    description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                                  template:
                                    type: string
                                    nullable: true
                                    maxLength: 2000
                                    description: The message, in the workflow template grammar ({{people.first_name}}).
                                  workflow_sid:
                                    type: string
                                    nullable: true
                                    description: "wf_wf_…: the workflow, when the Do is a workflow."
                                required:
                                  - "on"
                                  - do
                                  - template
                                  - workflow_sid
                            description: A switch per moment with its own Do under it; a kind absent is off.
                        required:
                          - moments
                      - type: object
                        properties:
                          do:
                            type: string
                            enum:
                              - pause_and_ask
                              - remove_from_workflows
                              - move_to_workflow
                            description: For a person in a workflow whose title or company moved.
                          workflow_sid:
                            type: string
                            nullable: true
                            description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                        required:
                          - do
                          - workflow_sid
                      - type: object
                        properties:
                          like:
                            type: object
                            properties:
                              "on":
                                type: boolean
                              reaction:
                                type: string
                                enum:
                                  - ai
                                  - like
                                  - celebrate
                                  - support
                                  - love
                                  - insightful
                                  - funny
                                description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                            required:
                              - "on"
                              - reaction
                          comment:
                            type: object
                            properties:
                              "on":
                                type: boolean
                              brief:
                                type: string
                                nullable: true
                                maxLength: 2000
                                description: What the AI writes the comment from; required while on.
                            required:
                              - "on"
                              - brief
                          per_person_weekly_cap:
                            type: integer
                            minimum: 1
                            maximum: 14
                            description: At most this many acts a week per person.
                          sender_profile_sid:
                            type: string
                            nullable: true
                            description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                        required:
                          - like
                          - comment
                          - per_person_weekly_cap
                          - sender_profile_sid
                      - type: object
                        properties:
                          do:
                            type: string
                            enum:
                              - pause_and_ask
                              - add_to_workflow
                            description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                          workflow_sid:
                            type: string
                            nullable: true
                            description: "wf_wf_…: required when the Do is a workflow."
                          pages:
                            type: array
                            nullable: true
                            items:
                              type: string
                            description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                        required:
                          - do
                          - workflow_sid
                          - pages
                      - type: object
                        properties: {}
                        description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
                    description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
                  audience:
                    description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
                  watch:
                    type: object
                    nullable: true
                    properties:
                      profile_days:
                        anyOf:
                          - type: number
                            enum:
                              - 7
                          - type: number
                            enum:
                              - 14
                          - type: number
                            enum:
                              - 30
                          - type: number
                            enum:
                              - 90
                          - {}
                        description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                      company_days:
                        anyOf:
                          - type: number
                            enum:
                              - 30
                          - type: number
                            enum:
                              - 90
                          - {}
                        description: "The company page every N days: 30 | 90; null = not watched."
                      posts_days:
                        anyOf:
                          - type: number
                            enum:
                              - 1
                          - type: number
                            enum:
                              - 3
                          - type: number
                            enum:
                              - 7
                          - {}
                        description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                      moments:
                        type: boolean
                        description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
                    required:
                      - profile_days
                      - company_days
                      - posts_days
                      - moments
                    description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
                  cadence:
                    type: string
                    enum:
                      - manual
                      - daily
                    description: "manual: runs on run_play; daily: runs by itself every day while enabled."
                  mode:
                    type: string
                    enum:
                      - ask_me
                      - automatic
                    description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
                  enabled:
                    type: boolean
                    description: The switch of a daily play; a manual play is always false.
                  enabled_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Who gave the consent (switched the play on).
                  enabled_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: when."
                  daily_credit_limit:
                    type: integer
                    nullable: true
                    description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
                  last_run_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  last_run_counts:
                    type: object
                    nullable: true
                    properties:
                      matched:
                        type: integer
                        minimum: 0
                        description: Rows the audience matched at the run (the tab's count under the filter).
                      acted:
                        type: integer
                        minimum: 0
                        description: Accounts appended to the queue, or people entered or re-entered.
                      skipped:
                        type: integer
                        minimum: 0
                        description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                      credits:
                        type: integer
                        minimum: 0
                        description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
                    required:
                      - matched
                      - acted
                      - skipped
                      - credits
                    description: What the last run did; null before the first run.
                  next_run_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live.
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - catalog_key
                  - name
                  - object_type
                  - action_type
                  - action
                  - watch
                  - cadence
                  - mode
                  - enabled
                  - enabled_by
                  - enabled_at
                  - daily_credit_limit
                  - last_run_at
                  - last_run_counts
                  - next_run_at
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Plays matching the filter scope.
            groups:
              type: object
              properties:
                object_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Plays per object (people | company).
                action_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Plays per action (find_people | add_to_workflow).
                cadence:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Plays per cadence (manual | daily).
                enabled:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: Plays per switch ("true" | "false").
              required:
                - object_type
                - action_type
                - cadence
                - enabled
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaytableFieldValuesRequest:
      type: object
      description: Request body of `search_playtable_field_values`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_vl_
                  description: Cell (playtable field value) sid (pt_vl_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_vl_
                    description: Cell (playtable field value) sid (pt_vl_…).
              additionalProperties: false
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
              additionalProperties: false
              description: Scope anchor (pt_tb_…).
            object_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: cr_pp_… / cr_co_… (mixed prefixes, not prefix-pinned); cell-level debugging scope for one row.
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
              additionalProperties: false
              description: "Residual inside scope: people | company."
            playtable_field_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_fd_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_fd_
              additionalProperties: false
              description: Per-field drill-down (pt_fd_…).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - empty
                    - queued
                    - running
                    - done
                    - error
                    - run_condition_not_met
                ne:
                  type: string
                  enum:
                    - empty
                    - queued
                    - running
                    - done
                    - error
                    - run_condition_not_met
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - empty
                      - queued
                      - running
                      - done
                      - error
                      - run_condition_not_met
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - empty
                      - queued
                      - running
                      - done
                      - error
                      - run_condition_not_met
              additionalProperties: false
              description: Error/progress drill-down; failed cells = in:["error","run_condition_not_met"].
            is_value_from_formula:
              type: object
              properties:
                eq:
                  type: boolean
              additionalProperties: false
              description: "Pinned-vs-formula audit: false on formula fields = manually pinned or tool-written."
            finished_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Last terminal write; is_null:true = never finalized.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - field
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - updated_at
                - finished_at
                - created_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaytableFieldValuesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                  object_sid:
                    type: string
                  playtable_field_sid:
                    type: string
                  value:
                    type: string
                    nullable: true
                  is_value_from_formula:
                    type: boolean
                  original_value:
                    type: string
                    nullable: true
                    description: "The system-produced value the FIRST manual overwrite snapshotted, what reset restores; null unless is_overwritten. The list surface nulls it like meta: read it on get, update, write and reset."
                  is_overwritten:
                    type: boolean
                    description: "The current value is a manual write over a system-produced one: the edited marker, and the one state reset accepts."
                  is_not_valid:
                    type: boolean
                    description: A manually written value that could not be converted to the column's type (text in a number column), stored raw and flagged; system writers coerce or null instead.
                  status:
                    type: string
                    enum:
                      - empty
                      - queued
                      - running
                      - done
                      - error
                      - run_condition_not_met
                  cost:
                    type: number
                    nullable: true
                  provider_sid:
                    type: string
                    nullable: true
                  meta:
                    type: object
                    nullable: true
                    properties:
                      run_sid:
                        type: string
                        nullable: true
                      steps:
                        type: array
                        items:
                          type: object
                          properties:
                            step_index:
                              type: number
                            tool_sid:
                              type: string
                            status:
                              type: string
                              enum:
                                - success
                                - failed
                                - skipped
                            cost:
                              type: number
                            error:
                              type: string
                              nullable: true
                            finished_at:
                              type: string
                              nullable: true
                            verdict:
                              type: string
                              nullable: true
                            email:
                              type: string
                              nullable: true
                          required:
                            - step_index
                            - tool_sid
                            - status
                            - cost
                            - error
                            - finished_at
                    required:
                      - run_sid
                      - steps
                  error_msg:
                    type: string
                    nullable: true
                  finished_at:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                  updated_at:
                    type: string
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - object_type
                  - object_sid
                  - playtable_field_sid
                  - value
                  - is_value_from_formula
                  - original_value
                  - is_overwritten
                  - is_not_valid
                  - status
                  - cost
                  - provider_sid
                  - meta
                  - error_msg
                  - finished_at
                  - created_at
                  - updated_at
              included:
                type: object
                properties:
                  field:
                    type: object
                    properties:
                      sid:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      category:
                        type: string
                      type:
                        type: string
                    required:
                      - sid
                      - name
                      - slug
                      - category
                      - type
                    description: "1:1 owning field (include[]=field): name, slug, category, type; config carries run_condition / nl_condition / preset."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: number
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                playtable_field_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
              required:
                - status
                - playtable_field_sid
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaytableFieldsRequest:
      type: object
      description: Request body of `search_playtable_fields`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Prefix-validated pt_fd_ sids.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Scope to one table; omit for the team-wide field library view.
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
                  description: "Object grid this field belongs to: people or company rows. Fixed at create."
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - people
                      - company
                    description: "Object grid this field belongs to: people or company rows. Fixed at create."
              additionalProperties: false
            category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - scalar
                    - widget
                    - action
                  description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - scalar
                      - widget
                      - action
                    description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
              additionalProperties: false
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - scalar_text
                    - scalar_number
                    - scalar_currency
                    - scalar_date
                    - scalar_url
                    - scalar_checkbox
                    - scalar_select
                    - scalar_multiselect
                    - scalar_image
                    - widget_data_source
                    - widget_tags
                    - widget_active_workflows
                    - widget_notes
                    - widget_company
                    - widget_linkedin_id
                    - widget_linkedin_channel
                    - widget_work_email
                    - widget_personal_email
                    - widget_email_channel
                    - widget_phones
                    - widget_phone_channel
                    - widget_last_touch
                    - widget_activity
                    - widget_deal_size
                    - widget_website
                    - widget_people_summary
                    - widget_ai_sdr
                    - action_ai_research
                    - action_waterfall
                    - action_gtm_tool
                    - action_find_people
                  description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - scalar_text
                      - scalar_number
                      - scalar_currency
                      - scalar_date
                      - scalar_url
                      - scalar_checkbox
                      - scalar_select
                      - scalar_multiselect
                      - scalar_image
                      - widget_data_source
                      - widget_tags
                      - widget_active_workflows
                      - widget_notes
                      - widget_company
                      - widget_linkedin_id
                      - widget_linkedin_channel
                      - widget_work_email
                      - widget_personal_email
                      - widget_email_channel
                      - widget_phones
                      - widget_phone_channel
                      - widget_last_touch
                      - widget_activity
                      - widget_deal_size
                      - widget_website
                      - widget_people_summary
                      - widget_ai_sdr
                      - action_ai_research
                      - action_waterfall
                      - action_gtm_tool
                      - action_find_people
                    description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - scalar_text
                      - scalar_number
                      - scalar_currency
                      - scalar_date
                      - scalar_url
                      - scalar_checkbox
                      - scalar_select
                      - scalar_multiselect
                      - scalar_image
                      - widget_data_source
                      - widget_tags
                      - widget_active_workflows
                      - widget_notes
                      - widget_company
                      - widget_linkedin_id
                      - widget_linkedin_channel
                      - widget_work_email
                      - widget_personal_email
                      - widget_email_channel
                      - widget_phones
                      - widget_phone_channel
                      - widget_last_touch
                      - widget_activity
                      - widget_deal_size
                      - widget_website
                      - widget_people_summary
                      - widget_ai_sdr
                      - action_ai_research
                      - action_waterfall
                      - action_gtm_tool
                      - action_find_people
                    description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
              additionalProperties: false
              description: nin excludes kinds wholesale, e.g. all widget types.
            slug:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact template-variable lookup.
            q:
              type: string
              maxLength: 128
              description: Full-text LIKE (prefix/infix) over name.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - playtable
              - deps
              - dependents
              - playtable_field_values_counts
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - name
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaytableFieldsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                    description: "Object grid this field belongs to: people or company rows. Fixed at create."
                  name:
                    type: string
                    description: Display label, freely editable.
                  slug:
                    type: string
                    description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
                  category:
                    type: string
                    enum:
                      - scalar
                      - widget
                      - action
                    description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
                  type:
                    type: string
                    enum:
                      - scalar_text
                      - scalar_number
                      - scalar_currency
                      - scalar_date
                      - scalar_url
                      - scalar_checkbox
                      - scalar_select
                      - scalar_multiselect
                      - scalar_image
                      - widget_data_source
                      - widget_tags
                      - widget_active_workflows
                      - widget_notes
                      - widget_company
                      - widget_linkedin_id
                      - widget_linkedin_channel
                      - widget_work_email
                      - widget_personal_email
                      - widget_email_channel
                      - widget_phones
                      - widget_phone_channel
                      - widget_last_touch
                      - widget_activity
                      - widget_deal_size
                      - widget_website
                      - widget_people_summary
                      - widget_ai_sdr
                      - action_ai_research
                      - action_waterfall
                      - action_gtm_tool
                      - action_find_people
                    description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
                  payload:
                    anyOf:
                      - type: object
                        properties:
                          formula:
                            type: string
                            nullable: true
                            maxLength: 8192
                            description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                          template:
                            type: string
                            nullable: true
                            maxLength: 8192
                            description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                          nl_formula:
                            type: string
                            nullable: true
                            maxLength: 2048
                            description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                          options:
                            type: array
                            nullable: true
                            items:
                              type: string
                            minItems: 1
                            description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                          currency:
                            type: string
                            nullable: true
                            pattern: ^[A-Z]{3}$
                            description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                          option_colors:
                            type: object
                            nullable: true
                            additionalProperties:
                              type: string
                              pattern: ^#[0-9a-f]{6}$
                            description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                        required:
                          - formula
                          - template
                          - nl_formula
                          - options
                          - currency
                          - option_colors
                      - type: object
                        properties: {}
                        additionalProperties: false
                        description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                      - type: object
                        properties:
                          workflow_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^wf_wf_
                            description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                        required:
                          - workflow_sid
                        additionalProperties: false
                      - type: object
                        properties:
                          stats_view:
                            type: string
                            enum:
                              - all
                              - last
                              - select
                            description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                          sender_profile_sid:
                            type: string
                            nullable: true
                            minLength: 18
                            maxLength: 18
                            pattern: ^ub_sp_
                            description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                        required:
                          - stats_view
                          - sender_profile_sid
                        additionalProperties: false
                      - type: object
                        properties:
                          prompt:
                            type: string
                            minLength: 1
                            maxLength: 8192
                            description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                          model:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                          output:
                            type: string
                            enum:
                              - text
                              - number
                              - select
                              - json
                            description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                          options:
                            type: array
                            nullable: true
                            items:
                              type: string
                            minItems: 1
                            description: Required (min 1) when output=select; null otherwise.
                          output_mapping:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                path:
                                  type: string
                                  minLength: 1
                                  maxLength: 512
                                  description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                                target:
                                  type: string
                                  minLength: 1
                                  maxLength: 128
                                  description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                              required:
                                - path
                                - target
                            maxItems: 20
                            description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                          web_search:
                            type: boolean
                            description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                        required:
                          - prompt
                          - model
                          - output
                          - options
                          - output_mapping
                      - type: object
                        properties:
                          steps:
                            type: array
                            items:
                              type: object
                              properties:
                                tool_sid:
                                  type: string
                                  minLength: 1
                                  description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                                params:
                                  type: object
                                  additionalProperties: {}
                                  description: Tool params; string values may be Twig templates over the same variable namespace.
                              required:
                                - tool_sid
                                - params
                            maxItems: 10
                            description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                          stop_on_first:
                            type: boolean
                            description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                          output_mapping:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                path:
                                  type: string
                                  minLength: 1
                                  maxLength: 512
                                  description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                                target:
                                  type: string
                                  minLength: 1
                                  maxLength: 128
                                  description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                              required:
                                - path
                                - target
                            maxItems: 20
                            description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                          verify:
                            type: object
                            nullable: true
                            properties:
                              tool_sid:
                                type: string
                                minLength: 1
                                description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                              params:
                                type: object
                                additionalProperties: {}
                                description: Tool params; string values may be Twig templates over the same variable namespace.
                            required:
                              - tool_sid
                              - params
                            description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                          accept_catch_all:
                            type: boolean
                            description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                        required:
                          - steps
                          - stop_on_first
                          - output_mapping
                      - type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: gtm-api tool registry sid (external format); existence + price validated at save.
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                          output_mapping:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                path:
                                  type: string
                                  minLength: 1
                                  maxLength: 512
                                  description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                                target:
                                  type: string
                                  minLength: 1
                                  maxLength: 128
                                  description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                              required:
                                - path
                                - target
                            maxItems: 20
                            description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                        required:
                          - tool_sid
                          - params
                          - output_mapping
                      - type: object
                        properties:
                          prompt:
                            type: string
                            nullable: true
                            maxLength: 2000
                            description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                          per_company_limit:
                            type: integer
                            minimum: 1
                            maximum: 25
                            description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                          data_source_sid:
                            type: string
                            nullable: true
                            description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                          qualify:
                            type: object
                            nullable: true
                            properties:
                              "on":
                                type: boolean
                                description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                              criterion:
                                type: string
                                nullable: true
                                minLength: 1
                                maxLength: 2000
                                description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                            required:
                              - "on"
                              - criterion
                            additionalProperties: false
                            description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                        required:
                          - prompt
                          - per_company_limit
                          - data_source_sid
                    description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
                  config:
                    type: object
                    properties:
                      auto_run:
                        type: boolean
                        description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                      run_condition:
                        anyOf:
                          - type: object
                            properties:
                              and:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                minItems: 1
                                maxItems: 20
                            required:
                              - and
                            additionalProperties: false
                          - type: object
                            properties:
                              or:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                minItems: 1
                                maxItems: 20
                            required:
                              - or
                            additionalProperties: false
                          - type: object
                            properties:
                              not:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - not
                            additionalProperties: false
                          - type: object
                            properties:
                              any:
                                type: object
                                properties:
                                  path:
                                    type: string
                                    minLength: 1
                                    description: Array-valued path - the only way to reach inside an array.
                                  where:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                required:
                                  - path
                                  - where
                                additionalProperties: false
                            required:
                              - any
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                              op:
                                type: object
                                properties:
                                  eq:
                                    anyOf:
                                      - type: string
                                      - type: number
                                      - type: boolean
                                  ne:
                                    anyOf:
                                      - type: string
                                      - type: number
                                      - type: boolean
                                  in:
                                    type: array
                                    items:
                                      anyOf:
                                        - type: string
                                        - type: number
                                        - type: boolean
                                    minItems: 1
                                    maxItems: 100
                                  nin:
                                    type: array
                                    items:
                                      anyOf:
                                        - type: string
                                        - type: number
                                        - type: boolean
                                    minItems: 1
                                    maxItems: 100
                                  gt:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  gte:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  lt:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  lte:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  is_null:
                                    type: boolean
                                  contains:
                                    type: string
                                    minLength: 1
                                  not_contains:
                                    type: string
                                    minLength: 1
                                  contains_any:
                                    type: array
                                    items:
                                      type: string
                                      minLength: 1
                                    minItems: 1
                                    maxItems: 50
                                  not_contains_any:
                                    type: array
                                    items:
                                      type: string
                                      minLength: 1
                                    minItems: 1
                                    maxItems: 50
                                  starts_with:
                                    type: string
                                    minLength: 1
                                additionalProperties: false
                            required:
                              - field
                              - op
                            additionalProperties: false
                          - {}
                        description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                      nl_condition:
                        type: string
                        nullable: true
                        maxLength: 2048
                        description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                      daily_credit_limit:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
                    required:
                      - auto_run
                      - run_condition
                      - nl_condition
                      - daily_credit_limit
                      - preset_sid
                  backfill:
                    type: object
                    nullable: true
                    properties:
                      status:
                        type: string
                        enum:
                          - queued
                          - running
                          - done
                          - failed
                      scanned:
                        type: integer
                        minimum: 0
                        description: Objects the scan has visited so far.
                      total:
                        type: integer
                        nullable: true
                        minimum: 0
                        description: The scan size, known once the job starts (null while queued).
                      queued_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the column started owing its backfill."
                      started_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when the job took it."
                      finished_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC: when it ended, done or failed."
                      error:
                        type: string
                        nullable: true
                        description: A reason token (backfill_failed) on failed, never an exception message.
                    required:
                      - status
                      - scanned
                      - total
                      - queued_at
                      - started_at
                      - finished_at
                      - error
                    description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - object_type
                  - name
                  - slug
                  - category
                  - type
                  - payload
                  - config
                  - backfill
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  playtable:
                    type: object
                    additionalProperties: {}
                    description: Owner playtable row (PlaytableDomain - owned by the playtables entity).
                  deps:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                        team_sid:
                          type: string
                        playtable_sid:
                          type: string
                        field_sid:
                          type: string
                          description: The consumer/derived field (pt_fd_…).
                        depends_on_field_sid:
                          type: string
                          description: The source field being read (pt_fd_…).
                        kind:
                          type: string
                          enum:
                            - formula
                            - prompt
                            - condition
                            - params
                          description: Construct that produced the edge (formula covers deep-ref extraction columns - edge lands on the root slug).
                        created_at:
                          type: string
                      required:
                        - sid
                        - team_sid
                        - playtable_sid
                        - field_sid
                        - depends_on_field_sid
                        - kind
                        - created_at
                    description: Edges this field READS (field_sid = this). Default limit 100, created_at ASC.
                  dependents:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                        team_sid:
                          type: string
                        playtable_sid:
                          type: string
                        field_sid:
                          type: string
                          description: The consumer/derived field (pt_fd_…).
                        depends_on_field_sid:
                          type: string
                          description: The source field being read (pt_fd_…).
                        kind:
                          type: string
                          enum:
                            - formula
                            - prompt
                            - condition
                            - params
                          description: Construct that produced the edge (formula covers deep-ref extraction columns - edge lands on the root slug).
                        created_at:
                          type: string
                      required:
                        - sid
                        - team_sid
                        - playtable_sid
                        - field_sid
                        - depends_on_field_sid
                        - kind
                        - created_at
                    description: Edges that READ this field (depends_on_field_sid = this) - the pre-delete safety check. Default limit 100, created_at ASC.
                  playtable_field_values_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                              - type: array
                                items: {}
                            description: Cells per status (empty | queued | running | done | error | run_condition_not_met).
                          playtable_field_sid:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                              - type: array
                                items: {}
                        required:
                          - status
                          - playtable_field_sid
                    required:
                      - total_count
                      - groups
                    description: Per-field cell execution progress.
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Rows matching the filter.
            groups:
              type: object
              properties:
                category:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                    - type: array
                      items: {}
                  description: Row counts per category (scalar | widget | action).
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                    - type: array
                      items: {}
                  description: Row counts per concrete field type.
                object_type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                    - type: array
                      items: {}
                  description: Row counts per object grid (people | company).
              required:
                - category
                - type
                - object_type
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaytableRunsRequest:
      type: object
      description: Request body of `search_playtable_runs`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_rn_
                  description: Playtable run sid (pt_rn_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rn_
                    description: Playtable run sid (pt_rn_…).
              additionalProperties: false
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                  description: Parent playtable sid (pt_tb_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                    description: Parent playtable sid (pt_tb_…).
              additionalProperties: false
              description: Per-table run history (pt_tb_…).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
              additionalProperties: false
              description: "Residual inside scope: people | company."
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - enrich
                    - export
                    - import
                    - bulk
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - enrich
                      - export
                      - import
                      - bulk
              additionalProperties: false
              description: enrich | export | import | bulk.
            created_by_actor_sid:
              type: object
              properties:
                eq:
                  type: string
              additionalProperties: false
              description: '"My runs" - matches created_by.actor_sid (projected column; user / api_key / agent actor sid).'
            finished_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "{ is_null: true } = active runs; datetime bounds for finished ones."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - progress
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - finished_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaytableRunsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  playtable_sid:
                    type: string
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                  type:
                    type: string
                    enum:
                      - enrich
                      - export
                      - import
                      - bulk
                  field_sids:
                    type: array
                    nullable: true
                    items:
                      type: string
                  scope:
                    type: object
                    nullable: true
                    properties:
                      object_sids:
                        type: array
                        nullable: true
                        items:
                          type: string
                      view_sid:
                        type: string
                        nullable: true
                      filter:
                        anyOf:
                          - type: object
                            properties:
                              and:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                minItems: 1
                                maxItems: 20
                            required:
                              - and
                            additionalProperties: false
                          - type: object
                            properties:
                              or:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                minItems: 1
                                maxItems: 20
                            required:
                              - or
                            additionalProperties: false
                          - type: object
                            properties:
                              not:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - not
                            additionalProperties: false
                          - type: object
                            properties:
                              any:
                                type: object
                                properties:
                                  path:
                                    type: string
                                    minLength: 1
                                    description: Array-valued path - the only way to reach inside an array.
                                  where:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                required:
                                  - path
                                  - where
                                additionalProperties: false
                            required:
                              - any
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                              op:
                                type: object
                                properties:
                                  eq:
                                    anyOf:
                                      - type: string
                                      - type: number
                                      - type: boolean
                                  ne:
                                    anyOf:
                                      - type: string
                                      - type: number
                                      - type: boolean
                                  in:
                                    type: array
                                    items:
                                      anyOf:
                                        - type: string
                                        - type: number
                                        - type: boolean
                                    minItems: 1
                                    maxItems: 100
                                  nin:
                                    type: array
                                    items:
                                      anyOf:
                                        - type: string
                                        - type: number
                                        - type: boolean
                                    minItems: 1
                                    maxItems: 100
                                  gt:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  gte:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  lt:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  lte:
                                    anyOf:
                                      - type: number
                                      - type: string
                                  is_null:
                                    type: boolean
                                  contains:
                                    type: string
                                    minLength: 1
                                  not_contains:
                                    type: string
                                    minLength: 1
                                  contains_any:
                                    type: array
                                    items:
                                      type: string
                                      minLength: 1
                                    minItems: 1
                                    maxItems: 50
                                  not_contains_any:
                                    type: array
                                    items:
                                      type: string
                                      minLength: 1
                                    minItems: 1
                                    maxItems: 50
                                  starts_with:
                                    type: string
                                    minLength: 1
                                additionalProperties: false
                            required:
                              - field
                              - op
                            additionalProperties: false
                          - {}
                        description: "Filter AST: and/or/not/any nodes (depth <= 5, root counts) over {field, op} leaves; op = >=1 of the §4.18 atoms; atoms AND."
                    required:
                      - object_sids
                      - view_sid
                      - filter
                  params_snapshot:
                    type: object
                    nullable: true
                    additionalProperties: {}
                  max_budget:
                    type: number
                    nullable: true
                  estimated_cost:
                    type: number
                    nullable: true
                  file_url:
                    type: string
                    nullable: true
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  finished_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - object_type
                  - type
                  - field_sids
                  - scope
                  - params_snapshot
                  - max_budget
                  - estimated_cost
                  - file_url
                  - created_by
                  - created_at
                  - finished_at
              included:
                type: object
                properties:
                  progress:
                    type: object
                    properties:
                      state:
                        type: string
                        enum:
                          - waiting
                          - resolving
                          - queued
                          - running
                          - finished
                          - cancelled
                        description: "Derived - precedence: cancelled > finished > running > queued. Terminal: finished, cancelled."
                      total_jobs:
                        type: number
                      pending_jobs:
                        type: number
                      processed_jobs:
                        type: number
                      failed_jobs:
                        type: number
                      cancelled_at:
                        type: string
                        nullable: true
                      spent_credits:
                        type: number
                    required:
                      - state
                      - total_jobs
                      - pending_jobs
                      - processed_jobs
                      - failed_jobs
                      - cancelled_at
                      - spent_credits
                    description: "1:1 derived progress (include[]=progress): state (queued|running|finished|cancelled), job counters from the Laravel batch, spent_credits from the ledger."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: number
            active_count:
              type: number
            groups:
              type: object
              properties:
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
              required:
                - type
          required:
            - total_count
            - active_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaytableViewsRequest:
      type: object
      description: Request body of `search_playtable_views`.
      properties:
        filter:
          type: object
          properties:
            q:
              type: string
              maxLength: 128
              description: Free-text over view names (MySQL LIKE prefix/infix).
            sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: View sid(s), pt_vw_ prefix.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Primary scope - views of one table (pt_tb_).
            object_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - people
                    - company
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - people
                      - company
              additionalProperties: false
              description: "Tab filter: people | company."
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact name match; substring goes through q.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live views)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - playtable
              - workflow_sources
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - name
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaytableViewsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: View sid (pt_vw_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  playtable_sid:
                    type: string
                    description: Owner playtable (pt_tb_…).
                  object_type:
                    type: string
                    enum:
                      - people
                      - company
                    description: "Object tab the view lenses: people | company. Fixed at create."
                  name:
                    type: string
                    description: View name; unique per (playtable, object_type) among live rows.
                  columns:
                    type: array
                    items:
                      type: object
                      properties:
                        column_type:
                          type: string
                          enum:
                            - group
                            - field
                            - field_group
                          description: "'field' = custom field of the table; 'group' = built-in attribute group of the object."
                        column_value:
                          type: string
                          nullable: true
                          description: "For 'field': pt_fd_ sid of the custom field. For 'group': built-in attribute-group key of the object_type. null for 'field_group'."
                        column_values:
                          type: array
                          nullable: true
                          items:
                            type: object
                            properties:
                              column_value:
                                type: string
                              width:
                                type: integer
                              is_visible:
                                type: boolean
                            required:
                              - column_value
                              - width
                              - is_visible
                          description: "'field_group' only: the band's member fields in grid order."
                        is_collapsed:
                          type: boolean
                          nullable: true
                          description: "'field_group' only: the band folded to its tag."
                        column_name:
                          type: string
                          nullable: true
                          description: Header label override; null = catalog / field name.
                        is_pinned:
                          type: boolean
                          description: Pinned to the left edge of the grid.
                        width:
                          type: number
                          description: Column width in px (40..1000).
                        is_visible:
                          type: boolean
                          description: Hidden columns keep their slot and order.
                      required:
                        - column_type
                        - column_value
                        - column_name
                        - is_pinned
                        - width
                        - is_visible
                    description: Ordered left→right; [] = base-attribute catalog fallback.
                  sort:
                    type: array
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          description: Built-in object column ("created_at", "full_name") or "record.<slug>" custom-field reference.
                        direction:
                          type: string
                          enum:
                            - asc
                            - desc
                          description: "'asc' | 'desc'."
                      required:
                        - field
                        - direction
                    description: Applied in array order; max 3 entries.
                  filter:
                    anyOf:
                      - type: object
                        properties:
                          and:
                            type: array
                            items:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            minItems: 1
                            maxItems: 20
                        required:
                          - and
                        additionalProperties: false
                      - type: object
                        properties:
                          or:
                            type: array
                            items:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            minItems: 1
                            maxItems: 20
                        required:
                          - or
                        additionalProperties: false
                      - type: object
                        properties:
                          not:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - not
                        additionalProperties: false
                      - type: object
                        properties:
                          any:
                            type: object
                            properties:
                              path:
                                type: string
                                minLength: 1
                                description: Array-valued path - the only way to reach inside an array.
                              where:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - path
                              - where
                            additionalProperties: false
                        required:
                          - any
                        additionalProperties: false
                      - type: object
                        properties:
                          field:
                            type: string
                            minLength: 1
                            description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                          op:
                            type: object
                            properties:
                              eq:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                                description: "Scalar equality. eq: null is rejected - use is_null."
                              ne:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                                description: "Scalar inequality. ne: null is rejected - use is_null."
                              in:
                                type: array
                                items:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                minItems: 1
                                maxItems: 100
                                description: Value in list, 1..100 scalars.
                              nin:
                                type: array
                                items:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                minItems: 1
                                maxItems: 100
                                description: Value not in list, 1..100 scalars.
                              gt:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: Greater than; string operand = ISO 8601 datetime.
                              gte:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: ">= bound; pair with lte in the SAME op for a range."
                              lt:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: Less than; string operand = ISO 8601 datetime.
                              lte:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: <= bound; pair with gte in the SAME op for a range.
                              is_null:
                                type: boolean
                                description: true = absent-or-null; false = present and non-null.
                              contains:
                                type: string
                                minLength: 1
                                description: Case-insensitive substring match.
                              not_contains:
                                type: string
                                minLength: 1
                                description: Negated case-insensitive substring match.
                              contains_any:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                maxItems: 50
                                description: 1..50 strings; true when ANY is a ci substring.
                              not_contains_any:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                maxItems: 50
                                description: 1..50 strings; true when NONE is a ci substring.
                              starts_with:
                                type: string
                                minLength: 1
                                description: Case-insensitive prefix match.
                            additionalProperties: false
                        required:
                          - field
                          - op
                        additionalProperties: false
                      - {}
                    description: Stored filter AST (§4.18-atom tree); null = whole tab.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that created the view (AccessIdentityValue).
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that soft-deleted the view; null while live.
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete).
                required:
                  - sid
                  - team_sid
                  - playtable_sid
                  - object_type
                  - name
                  - columns
                  - sort
                  - filter
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  playtable:
                    type: object
                    additionalProperties: {}
                    description: Owner playtable row (PlaytableDomain - entities/playtables.md). Present when requested and found.
                  workflow_sources:
                    type: array
                    items:
                      type: object
                      additionalProperties: {}
                    description: Sources consuming this view as an audience (WorkflowSourceDomain - entities/workflow_sources.md); max 20, created_at DESC.
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Rows matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                object_type:
                  type: object
                  properties:
                    people:
                      type: integer
                      minimum: 0
                    company:
                      type: integer
                      minimum: 0
                  required:
                    - people
                    - company
                  description: View distribution across the two object tabs (feeds tab badges).
              required:
                - object_type
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchPlaytablesRequest:
      type: object
      description: Request body of `search_playtables`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Prefix-validated pt_tb_ sid(s).
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact match (dedup checks); substring matching goes through q.
            agent_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_ag_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_ag_
                is_null:
                  type: boolean
              additionalProperties: false
              description: The AI SDR the table picked (ub_ag_…); is_null:true = the tables on the team's default agent.
            q:
              type: string
              maxLength: 128
              description: Full-text LIKE (prefix/infix) over name + description.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - views
              - fields
              - data_sources_counts
              - people_counts
              - companies_counts
              - workflows_counts
              - outreach_counts
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - updated_at
                - name
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchPlaytablesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  name:
                    type: string
                  description:
                    type: string
                    nullable: true
                  agent_sid:
                    type: string
                    nullable: true
                    description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
                  company_default_view_sid:
                    type: string
                    description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
                  people_default_view_sid:
                    type: string
                    description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
                  config:
                    type: object
                    properties:
                      auto_run:
                        type: boolean
                        description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
                    required:
                      - auto_run
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - name
                  - description
                  - agent_sid
                  - company_default_view_sid
                  - people_default_view_sid
                  - config
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  views:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: PlaytableViewDomain rows (1:N, default limit 50, created_at ASC) - see ./playtable_views.md.
                  fields:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: PlaytableFieldDomain rows (1:N, default limit 100, created_at ASC) - see ./playtable_fields.md.
                  data_sources_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                    description: "DataSourceCounts of the sources feeding the table (every live one, no view scope): total_count + groups by status / type / object_type - see ./data_sources.md."
                  people_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      indexing_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                      - indexing_count
                    description: "Reduced people count: total_count scoped to the people tab's DEFAULT VIEW filter (ES-served), indexing_count = the table's rows not in the index yet - see ./people.md."
                  companies_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      indexing_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                      - indexing_count
                    description: "Reduced company count: total_count scoped to the companies tab's DEFAULT VIEW filter (ES-served), indexing_count = the table's rows not in the index yet - see ./companies.md."
                  workflows_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                    required:
                      - total_count
                    description: "WorkflowCounts of the workflows whose home is the table: total_count + groups.status - see ./workflows.md."
                  outreach_counts:
                    type: object
                    properties:
                      linkedin:
                        type: object
                        properties:
                          invited:
                            type: integer
                            minimum: 0
                          accepted:
                            type: integer
                            minimum: 0
                          messaged:
                            type: integer
                            minimum: 0
                          replied:
                            type: integer
                            minimum: 0
                        required:
                          - invited
                          - accepted
                          - messaged
                          - replied
                      email:
                        type: object
                        properties:
                          emailed:
                            type: integer
                            minimum: 0
                          replied:
                            type: integer
                            minimum: 0
                        required:
                          - emailed
                          - replied
                    required:
                      - linkedin
                      - email
                    description: "PlaytableOutreachCounts (2026-09-26): those workflows' outreach counted in PEOPLE, per channel, the list's accept / reply rates. linkedin.invited / accepted: people a connection request went to / who accepted; linkedin.messaged: people a message reached (a message, an InMail, or the invite's note, which LinkedIn delivers as the thread's first message at the accept); linkedin.replied: people who answered at or after they were messaged; email.emailed / replied: the same by email. A rate is replied / messaged (emailed), people over people - see ./activities.md."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Playtable rows matching the filter scope.
            groups:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Always empty - no group axes ('sid' is metrics-only). PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchResultPagesRequest:
      type: object
      description: Request body of `search_result_pages`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_rp_
                  description: Result page sid (pt_rp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_rp_
                    description: Result page sid (pt_rp_…).
              additionalProperties: false
              description: Prefix-validated pt_rp_ sid(s) - also the point-lookup path (no get tool).
            owner_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: "Whose pages: the publisher's actor sid (us_mb_…)."
            scope:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - workspace
                    - playtable
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - workspace
                      - playtable
              additionalProperties: false
              description: workspace for the Dashboard's machine, playtable for a table's flow.
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The table of a table's page (pt_tb_…); { is_null: true } picks the workspace's pages."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range over the first publish; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range over the last publish.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live pages); { is_null: false } lists the ones taken down."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - updated_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchResultPagesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Result page sid (pt_rp_…); the 12 characters after pt_rp_ are the key, the last segment of public_url.
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  owner_sid:
                    type: string
                    description: "Who published it (us_mb_ user, id_ak_ API key). One live page per owner and chart: a teammate's page of the same chart is another page."
                  scope:
                    type: string
                    enum:
                      - workspace
                      - playtable
                    description: "What the picture is of: workspace = the Dashboard's machine, every table; playtable = one table's flow (playtable_sid)."
                  playtable_sid:
                    type: string
                    nullable: true
                    description: The table of a playtable page (pt_tb_…); null for a workspace page.
                  headline:
                    type: string
                    description: "The picture's headline (1..160): the page's title and og:title."
                  description:
                    type: string
                    description: The line under the headline (1..400), og:description, in the publisher's language.
                  brand_name:
                    type: string
                    description: "Who the picture says made it (1..80): GetSales, or a reseller's name on a whitelabel host; og:site_name."
                  locale:
                    type: string
                    enum:
                      - en
                      - es
                      - fr
                      - pt
                      - de
                      - hi
                      - zh
                      - ar
                      - ru
                    description: The language the headline and the description are written in.
                  version:
                    type: integer
                    minimum: 1
                    description: How many different pictures the page has carried; a publish of a new picture at the same address bumps it.
                  public_url:
                    type: string
                    description: The page's public address, stamped at the first publish and never moved. A network is handed public_url?v={version} past version 1.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor whose publish minted the page (AccessIdentityValue).
                  created_at:
                    type: string
                    description: ISO 8601 UTC - the first publish.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC - the last publish that changed the picture or the words.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live, set = taken down (its address answers 404).
                required:
                  - sid
                  - team_sid
                  - owner_sid
                  - scope
                  - playtable_sid
                  - headline
                  - description
                  - brand_name
                  - locale
                  - version
                  - public_url
                  - created_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Pages matching the filter (full filter scope, not the page).
            groups:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Always empty - no group axis. PHP serialises an empty map as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchStoplistEntriesRequest:
      type: object
      description: Request body of `search_stoplist_entries`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^sl_sl_
                  description: Stoplist entry sid (sl_sl_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^sl_sl_
                    description: Stoplist entry sid (sl_sl_…).
              additionalProperties: false
              description: Entry sid(s), sl_sl_ prefix.
            identifier_type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ln_member_id
                    - email
                    - domain
                    - ln_nickname
                    - company_ln_nickname
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ln_member_id
                      - email
                      - domain
                      - ln_nickname
                      - company_ln_nickname
              additionalProperties: false
              description: ln_member_id | email | domain | ln_nickname | company_ln_nickname.
            value:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 1
                  maxLength: 511
                in:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 511
              additionalProperties: false
              description: Exact "is X listed?" check - raw input accepted, normalized before compare.
            source:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - manual
                    - csv_import
                    - api
                    - unsubscribe
                    - complaint
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - manual
                      - csv_import
                      - api
                      - unsubscribe
                      - complaint
              additionalProperties: false
              description: "Write path: manual | csv_import | api | unsubscribe."
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Entries a retired csv_stoplist data source promoted before 2026-09-20 (ds_sc_…); is_null:true = every row written since.
            q:
              type: string
              maxLength: 128
              description: Free text over normalized values (MySQL LIKE prefix/infix) - "anything with acme in it".
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live entries); { is_null: false } = un-stoplist audit."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchStoplistEntriesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Stoplist entry sid (sl_sl_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  identifier_type:
                    type: string
                    enum:
                      - ln_member_id
                      - email
                      - domain
                      - ln_nickname
                      - company_ln_nickname
                    description: "What kind of identifier this row blocks: ln_member_id | email | domain | ln_nickname | company_ln_nickname."
                  value:
                    type: string
                    description: "NORMALIZED identifier: the member id as base-10 digits (698599037), lowercase email, bare hostname (acme.com), or a lowercased vanity slug (janecooper, acme-corp). Raw input is not stored, and a URL or a URN never is."
                  source:
                    type: string
                    enum:
                      - manual
                      - csv_import
                      - api
                      - unsubscribe
                      - complaint
                    description: "Write path: manual | csv_import | api | unsubscribe. Stamped by the server; csv_import is the one value a user actor may name on create."
                  data_source_sid:
                    type: string
                    nullable: true
                    description: Provenance of a row the retired csv_stoplist data source promoted before 2026-09-20 (ds_sc_…); null on every row written since, the csv_import ones included.
                  data_source_item_sid:
                    type: string
                    nullable: true
                    description: Provenance of the staged row that produced such an entry (ds_it_…); null on every row written since.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that created the entry (AccessIdentityValue).
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that un-stoplisted the entry; null while live.
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC; always equals created_at - rows have no update path.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live entry (soft delete).
                required:
                  - sid
                  - team_sid
                  - identifier_type
                  - value
                  - source
                  - data_source_sid
                  - data_source_item_sid
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Entries matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                identifier_type:
                  anyOf:
                    - type: object
                      properties:
                        ln_member_id:
                          type: integer
                          minimum: 0
                        email:
                          type: integer
                          minimum: 0
                        domain:
                          type: integer
                          minimum: 0
                        ln_nickname:
                          type: integer
                          minimum: 0
                        company_ln_nickname:
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: List composition by identifier kind.
                source:
                  anyOf:
                    - type: object
                      properties:
                        manual:
                          type: integer
                          minimum: 0
                        csv_import:
                          type: integer
                          minimum: 0
                        api:
                          type: integer
                          minimum: 0
                        unsubscribe:
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: Where the blocks came from.
              required:
                - identifier_type
                - source
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchTagsRequest:
      type: object
      description: Request body of `search_tags`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_tg_
                  description: Tag sid (cr_tg_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                    description: Tag sid (cr_tg_…).
              additionalProperties: false
              description: Prefix-validated cr_tg_ sid(s) - resolve sids back to names.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact label lookup (resolve name → sid); substring goes through q.
            q:
              type: string
              maxLength: 128
              description: Free-text MySQL LIKE (prefix/infix) over name - small per-team list, no FULLTEXT.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live tags)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - name
                - created_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchTagsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Tag sid (cr_tg_…) - the value objects store in tag_sids[].
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  name:
                    type: string
                    description: Label text, stored as entered (original casing); unique per team case-insensitively among live rows.
                  color:
                    type: string
                    nullable: true
                    description: Chip color "#rrggbb" (lowercase hex); null = client default palette.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that created the tag (AccessIdentityValue).
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete).
                required:
                  - sid
                  - team_sid
                  - name
                  - color
                  - created_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Tags matching the filter (full filter scope, not the page).
            groups:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Always empty - no group axes (name is unique per row, color is cosmetic). PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowAttachmentsRequest:
      type: object
      description: Request body of `search_workflow_attachments`.
      properties:
        filter:
          type: object
          properties:
            q:
              type: string
              maxLength: 128
              description: Free text over name (MySQL LIKE, prefix/infix - a small per-team library, no FULLTEXT).
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_at_
                  description: Attachment sid (wf_at_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_at_
                    description: Attachment sid (wf_at_…).
              additionalProperties: false
              description: Prefix-validated wf_at_ sid(s) - also the point-lookup path (no get tool), and how a step ref is resolved to a live row.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: Exact file name; substring matching goes through q.
            mime_type:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
              additionalProperties: false
              description: "Exact media type, e.g. { eq: 'application/pdf' }. There is no family prefix match: pass the types you want in `in`."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range over the upload time; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live files)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - name
                - created_at
                - size_bytes
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowAttachmentsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Attachment sid (wf_at_…) - the value an email_send step stores in its attachments[].sid.
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  name:
                    type: string
                    description: "File name the recipient sees (1..255): the name given at upload, else the upload's own. Fixed at upload."
                  mime_type:
                    type: string
                    description: Media type as sniffed at upload (1..127), e.g. 'application/pdf'; 'application/octet-stream' when it could not be sniffed.
                  size_bytes:
                    type: integer
                    minimum: 0
                    description: File size in bytes, 0..10485760 (10 MB, the upload ceiling).
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that uploaded the file (AccessIdentityValue).
                  created_at:
                    type: string
                    description: ISO 8601 UTC - the upload time.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete).
                required:
                  - sid
                  - team_sid
                  - name
                  - mime_type
                  - size_bytes
                  - created_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                additionalProperties: {}
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Files matching the filter (full filter scope, not the page).
            groups:
              anyOf:
                - type: object
                  additionalProperties: {}
                - type: array
                  items: {}
              description: Always empty - the library has no bounded group axis. PHP serialises an empty map as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowRecordsRequest:
      type: object
      description: Request body of `search_workflow_records`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_rc_
                  description: Workflow record sid (wf_rc_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_rc_
                    description: Workflow record sid (wf_rc_…).
              additionalProperties: false
              description: Prefix-validated wf_rc_ sid(s); also the single-row read (no get tool).
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: Progress-board scope (wf_wf_…).
            workflow_version_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_vr_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_vr_
              additionalProperties: false
              description: '"Who is still on the old version" (wf_vr_…).'
            people_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
              additionalProperties: false
              description: Person card (cr_pp_…); bulk ops take sids from people search first.
            entered_via_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_sr_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_sr_
              additionalProperties: false
              description: Per-source cohort (wf_sr_…).
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Per-sender load (ub_sp_…); is_null:true = unpinned (no send steps).
            current_step_id:
              type: object
              properties:
                eq:
                  type: integer
                in:
                  type: array
                  items:
                    type: integer
              additionalProperties: false
              description: Step column of the board (int step id); meaningful only with a workflow_sid filter.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - waiting_limit
                    - blocked
                    - active
                    - waiting
                    - paused_on_reply
                    - paused_manual
                    - paused_blocked
                    - failed
                    - completed
                    - exited
                ne:
                  type: string
                  enum:
                    - waiting_limit
                    - blocked
                    - active
                    - waiting
                    - paused_on_reply
                    - paused_manual
                    - paused_blocked
                    - failed
                    - completed
                    - exited
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting_limit
                      - blocked
                      - active
                      - waiting
                      - paused_on_reply
                      - paused_manual
                      - paused_blocked
                      - failed
                      - completed
                      - exited
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - waiting_limit
                      - blocked
                      - active
                      - waiting
                      - paused_on_reply
                      - paused_manual
                      - paused_blocked
                      - failed
                      - completed
                      - exited
              additionalProperties: false
            last_touch_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Staleness - "no movement since …"; ISO 8601 bounds.
            finished_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "{ is_null: true } = live records; datetime bounds = terminal cohort."
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Enrollment window; ISO 8601 bounds, combine in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows); set only by parent cascades."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - people
              - workflow
              - sender_profile
              - workflow_tasks_counts
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - last_touch_at
                - finished_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowRecordsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  workflow_sid:
                    type: string
                    description: wf_wf_… owning workflow; DB-UNIQUE together with people_sid - one row per (workflow, person) pair, forever - see ./workflows.md.
                  workflow_version_sid:
                    type: string
                    description: wf_vr_… version pinned at enrollment - the record executes that step graph even after newer publishes - see ./workflow_versions.md.
                  people_sid:
                    type: string
                    description: cr_pp_… the enrolled person; second half of the DB-UNIQUE pair - see ./people.md.
                  entered_via_source_sid:
                    type: string
                    description: wf_sr_… entry point that produced the row (immutable audit) - see ./workflow_sources.md.
                  sender_profile_sid:
                    type: string
                    nullable: true
                    description: ub_sp_… sender pinned at enrollment; null when the version has no send steps; re-resolved at next dispatch if the profile is deleted - see ./sender_profiles.md.
                  current_step_id:
                    type: number
                    description: Small int step id inside the pinned version steps JSON (server-assigned, immutable, never reused) - a JSON node pointer, not a sid or row.
                  status:
                    type: string
                    enum:
                      - waiting_limit
                      - blocked
                      - active
                      - waiting
                      - paused_on_reply
                      - paused_manual
                      - paused_blocked
                      - failed
                      - completed
                      - exited
                  entered_at:
                    type: string
                    nullable: true
                  touches_done:
                    type: integer
                    minimum: 0
                  rotations_done:
                    type: integer
                    minimum: 0
                  error_code:
                    type: string
                    nullable: true
                    description: Machine code of the last failure, from the failing task result (max 64).
                  error_message:
                    type: string
                    nullable: true
                    description: Human-readable detail of the last failure (max 1024).
                  last_touch_at:
                    type: string
                    description: ISO 8601 UTC - last step advance or status change; the staleness clock.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - stamped once when status enters a terminal state; null while live.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - workflow_sid
                  - workflow_version_sid
                  - people_sid
                  - entered_via_source_sid
                  - sender_profile_sid
                  - current_step_id
                  - status
                  - entered_at
                  - touches_done
                  - rotations_done
                  - error_code
                  - error_message
                  - last_touch_at
                  - finished_at
                  - created_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  people:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: PeopleDomain (1:1 via people_sid) - names/urls for board rendering - see ./people.md.
                  workflow:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: WorkflowDomain (1:1 via workflow_sid) - see ./workflows.md.
                  sender_profile:
                    type: object
                    nullable: true
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: SenderProfileDomain (1:1 via sender_profile_sid); null when unpinned - see ./sender_profiles.md.
                  workflow_tasks_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Funnel by WorkflowTaskStatusEnum - this record's execution shape.
                          type:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                        required:
                          - status
                          - type
                    required:
                      - total_count
                      - groups
                    description: "WorkflowTaskCounts computed over { workflow_record_sid: parent.sid } - status/type distribution of this record's tasks without loading rows (§4.17 parent-include) - see ./workflow_tasks.md."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Records matching the filter scope.
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: The funnel axis - map keyed by the 8 WorkflowRecordStatusEnum values.
                workflow_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Per-workflow distribution across the team.
                current_step_id:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Board columns - keys are STRINGIFIED step ids; read with a workflow_sid filter in scope.
                sender_profile_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Per-sender load; "null" bucket = unpinned (no send steps).
                entered_via_source_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Per-source funnel.
              required:
                - status
                - workflow_sid
                - current_step_id
                - sender_profile_sid
                - entered_via_source_sid
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowSourcesRequest:
      type: object
      description: Request body of `search_workflow_sources`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_sr_
                  description: Workflow source sid (wf_sr_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_sr_
                    description: Workflow source sid (wf_sr_…).
              additionalProperties: false
              description: Prefix-validated wf_sr_ sid(s).
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
              additionalProperties: false
              description: Primary scope - the audience feeds of one campaign (wf_wf_…).
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - view
                    - filter
                    - manual
                    - event
                ne:
                  type: string
                  enum:
                    - view
                    - filter
                    - manual
                    - event
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - view
                      - filter
                      - manual
                      - event
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - view
                      - filter
                      - manual
                      - event
              additionalProperties: false
              description: view | filter | manual.
            auto_add:
              type: object
              properties:
                eq:
                  type: boolean
              additionalProperties: false
              description: true = live feeds; false = dormant pointers + manual buckets.
            view_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_vw_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_vw_
                is_null:
                  type: boolean
              additionalProperties: false
              description: 'Reverse lookup: "which workflows feed from this view" (pt_vw_…).'
            q:
              type: string
              maxLength: 128
              description: Free text over name (MySQL LIKE prefix/infix).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live feeds)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - workflow
              - view
              - workflow_records_counts
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - name
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowSourcesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Source sid (wf_sr_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  workflow_sid:
                    type: string
                    description: "[ro] Parent workflow (wf_wf_…) - see ./workflows.md."
                  view_sid:
                    type: string
                    nullable: true
                    description: Audience view (pt_vw_…) - set on type=view only, null otherwise; repointable via update - see ./playtable_views.md.
                  name:
                    type: string
                    nullable: true
                    description: Optional label ("Conference batch"), max 255; null = unlabeled.
                  type:
                    type: string
                    enum:
                      - view
                      - filter
                      - manual
                      - event
                    description: "[ro] view = playtable view membership | filter = inline AST | manual = hand-picked people. Immutable - repoint = delete + create."
                  event:
                    type: string
                    nullable: true
                    enum:
                      - linkedin_connection_request_accepted
                      - linkedin_message_replied
                      - linkedin_inmail_replied
                      - email_replied
                      - email_opened
                      - email_link_clicked
                      - linkedin_invitation_received
                      - linkedin_followed
                      - website_visited
                      - website_key_page_visited
                      - website_form_submitted
                    description: "type=event only: the activity type that enrolls a person (required at create for an event source, 422 otherwise); null on the other types."
                  filter:
                    anyOf:
                      - type: object
                        properties:
                          and:
                            type: array
                            items:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            minItems: 1
                            maxItems: 20
                        required:
                          - and
                        additionalProperties: false
                      - type: object
                        properties:
                          or:
                            type: array
                            items:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            minItems: 1
                            maxItems: 20
                        required:
                          - or
                        additionalProperties: false
                      - type: object
                        properties:
                          not:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - not
                        additionalProperties: false
                      - type: object
                        properties:
                          any:
                            type: object
                            properties:
                              path:
                                type: string
                                minLength: 1
                                description: Array-valued path - the only way to reach inside an array.
                              where:
                                type: object
                                additionalProperties: {}
                                description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                            required:
                              - path
                              - where
                            additionalProperties: false
                        required:
                          - any
                        additionalProperties: false
                      - type: object
                        properties:
                          field:
                            type: string
                            minLength: 1
                            description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                          op:
                            type: object
                            properties:
                              eq:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                                description: "Scalar equality. eq: null is rejected - use is_null."
                              ne:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                                description: "Scalar inequality. ne: null is rejected - use is_null."
                              in:
                                type: array
                                items:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                minItems: 1
                                maxItems: 100
                                description: Value in list, 1..100 scalars.
                              nin:
                                type: array
                                items:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                minItems: 1
                                maxItems: 100
                                description: Value not in list, 1..100 scalars.
                              gt:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: Greater than; string operand = ISO 8601 datetime.
                              gte:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: ">= bound; pair with lte in the SAME op for a range."
                              lt:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: Less than; string operand = ISO 8601 datetime.
                              lte:
                                anyOf:
                                  - type: number
                                  - type: string
                                description: <= bound; pair with gte in the SAME op for a range.
                              is_null:
                                type: boolean
                                description: true = absent-or-null; false = present and non-null.
                              contains:
                                type: string
                                minLength: 1
                                description: Case-insensitive substring match.
                              not_contains:
                                type: string
                                minLength: 1
                                description: Negated case-insensitive substring match.
                              contains_any:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                maxItems: 50
                                description: 1..50 strings; true when ANY is a ci substring.
                              not_contains_any:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                maxItems: 50
                                description: 1..50 strings; true when NONE is a ci substring.
                              starts_with:
                                type: string
                                minLength: 1
                                description: Case-insensitive prefix match.
                            additionalProperties: false
                        required:
                          - field
                          - op
                        additionalProperties: false
                      - {}
                    description: Inline audience AST (type=filter only, null otherwise) over the team's people; ES resolves membership, record.<slug> leaves resolve per person's playtable (missing slug ⇒ false).
                  auto_add:
                    type: boolean
                    description: "Poller toggle (view/filter): true = every cycle (~10 min) ES lists current audience members and MySQL decides entry; false = dormant pointer. Always false on manual."
                  active_limit:
                    type: integer
                    nullable: true
                    minimum: 1
                    description: Max simultaneous in-flight (non-terminal) records entered via THIS source; null = unlimited. Reached => new candidates wait (blocked_limit_count).
                  coworkers_limit:
                    type: integer
                    nullable: true
                    minimum: 1
                    description: Max simultaneous in-flight records from THIS source for people of the SAME company; null = unlimited. Reached for a company => that company's candidates wait.
                  entered_count:
                    type: integer
                    minimum: 0
                    description: "[ro] Total workflow_records ever inserted via this source - monotonic on ALL types (cache of the entered_via_source_sid count)."
                  blocked_stoplisted_count:
                    type: integer
                    minimum: 0
                    description: "[ro] Stoplist entry blocks. view/filter: LIVE backlog gauge, recomputed each poll cycle over current audience members (un-stoplisted people drop out and enter); manual: cumulative per call."
                  blocked_duplicate_in_workflow_count:
                    type: integer
                    minimum: 0
                    description: "[ro] Poller-only: candidates skipped as already enrolled in this workflow via ANY source (auto_add never re-enters). view/filter: live gauge per poll cycle; ~0 on manual (add-people re-enters instead)."
                  blocked_limit_count:
                    type: integer
                    minimum: 0
                    description: "[ro] Candidates WAITING because active_limit / coworkers_limit is reached this cycle; they enter automatically once a slot frees. view/filter: live gauge; manual: cumulative per call."
                  blocked_other_count:
                    type: integer
                    minimum: 0
                    description: "[ro] Blocked as deleted/missing/otherwise ineligible people. view/filter: live gauge per poll cycle; manual: cumulative per call."
                  last_evaluated_at:
                    type: string
                    nullable: true
                    description: "[ro] Last poll cycle (view/filter) or last add-people / inline-create batch (manual); ISO 8601 UTC, null = never evaluated."
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that attached the feed (AccessIdentityValue).
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: Actor that soft-deleted the feed (own verb or workflows.delete cascade); null while live.
                  created_at:
                    type: string
                    description: ISO 8601 UTC.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC; null = live (soft delete - the poller gates on it).
                required:
                  - sid
                  - team_sid
                  - workflow_sid
                  - view_sid
                  - name
                  - type
                  - filter
                  - auto_add
                  - active_limit
                  - coworkers_limit
                  - entered_count
                  - blocked_stoplisted_count
                  - blocked_duplicate_in_workflow_count
                  - blocked_limit_count
                  - blocked_other_count
                  - last_evaluated_at
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  workflow:
                    type: object
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: Parent WorkflowDomain (1:1 via workflow_sid) - see ./workflows.md.
                  view:
                    type: object
                    nullable: true
                    properties:
                      sid:
                        type: string
                    required:
                      - sid
                    description: PlaytableViewDomain (1:1 via view_sid); null unless type=view - see ./playtable_views.md.
                  workflow_records_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: Downstream journey funnel keyed by WorkflowRecordStatusEnum.
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                    description: "WorkflowRecordCounts computed over { entered_via_source_sid: parent.sid } - the status funnel of everyone who entered through this source, without loading rows (§4.17 parent-include) - see ./workflow_records.md."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Source rows matching the filter scope.
            groups:
              type: object
              properties:
                type:
                  anyOf:
                    - type: object
                      properties:
                        view:
                          type: integer
                          minimum: 0
                        filter:
                          type: integer
                          minimum: 0
                        manual:
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: Feed distribution across the three source types; absent key = zero (PHP empty map serialises as []).
                auto_add:
                  anyOf:
                    - type: object
                      properties:
                        "true":
                          type: integer
                          minimum: 0
                        "false":
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: Live feeds vs dormant pointers/manual buckets (JSON object keys are strings); absent key = zero (PHP empty map serialises as []).
                workflow_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Sources-per-workflow map keyed by wf_wf_ sid; PHP serialises an empty map as [].
              required:
                - type
                - auto_add
                - workflow_sid
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowTasksRequest:
      type: object
      description: Request body of `search_workflow_tasks`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_tk_
                  description: Workflow task sid (wf_tk_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_tk_
                    description: Workflow task sid (wf_tk_…).
              additionalProperties: false
              description: Task sid(s), wf_tk_ prefix - also the point-lookup path (no get tool).
            initiator:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - workflow_record
                    - play
                    - user
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - workflow_record
                      - play
                      - user
              additionalProperties: false
              description: 'Who bore the task (2026-10-14). Needs me = { eq: "play" } with status eq pending: the drafts and questions waiting in the Signals feed.'
            play_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_pl_
                  description: Play sid (pt_pl_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_pl_
                    description: Play sid (pt_pl_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: One play's acts (pt_pl_…); is_null:true = a journey's tasks.
            trigger_activity_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_ac_
                  description: Activity (fact) sid (cr_ac_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_ac_
                    description: Activity (fact) sid (cr_ac_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The acts under one event (cr_ac_…): what a play left waiting or did on that fact."
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: Workflow sid (wf_wf_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Workflow sid (wf_wf_…).
              additionalProperties: false
              description: Per-campaign execution view (wf_wf_…).
            workflow_record_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_rc_
                  description: Workflow record sid (wf_rc_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_rc_
                    description: Workflow record sid (wf_rc_…).
              additionalProperties: false
              description: One record's task history (wf_rc_…).
            people_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
              additionalProperties: false
              description: Person timeline (cr_pp_…); resolve names via people search first.
            sender_profile_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                  description: Sender profile sid (ub_sp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                    description: Sender profile sid (ub_sp_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: Per-sender queue/load (ub_sp_…); is_null:true = orchestration-class.
            step_id:
              type: object
              properties:
                eq:
                  type: integer
                  minimum: 0
                in:
                  type: array
                  items:
                    type: integer
                    minimum: 0
              additionalProperties: false
              description: Step drill-down - meaningful only combined with a workflow_sid filter.
            type:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - linkedin_send_connection_request
                    - linkedin_send_message
                    - linkedin_send_inmail
                    - linkedin_visit_profile
                    - linkedin_endorse_skills
                    - linkedin_withdraw_connection_request
                    - email_send
                    - wait
                    - wait_for_event
                    - condition
                    - api_call
                    - ask_ai
                    - manual_task
                    - linkedin_like_latest_post
                    - linkedin_comment_latest_post
                    - ab_test
                    - move_to_workflow
                    - add_tag
                    - remove_tag
                    - set_field
                    - change_sender
                    - run_column
                ne:
                  type: string
                  enum:
                    - linkedin_send_connection_request
                    - linkedin_send_message
                    - linkedin_send_inmail
                    - linkedin_visit_profile
                    - linkedin_endorse_skills
                    - linkedin_withdraw_connection_request
                    - email_send
                    - wait
                    - wait_for_event
                    - condition
                    - api_call
                    - ask_ai
                    - manual_task
                    - linkedin_like_latest_post
                    - linkedin_comment_latest_post
                    - ab_test
                    - move_to_workflow
                    - add_tag
                    - remove_tag
                    - set_field
                    - change_sender
                    - run_column
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                      - linkedin_send_message
                      - linkedin_send_inmail
                      - linkedin_visit_profile
                      - linkedin_endorse_skills
                      - linkedin_withdraw_connection_request
                      - email_send
                      - wait
                      - wait_for_event
                      - condition
                      - api_call
                      - ask_ai
                      - manual_task
                      - linkedin_like_latest_post
                      - linkedin_comment_latest_post
                      - ab_test
                      - move_to_workflow
                      - add_tag
                      - remove_tag
                      - set_field
                      - change_sender
                      - run_column
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                      - linkedin_send_message
                      - linkedin_send_inmail
                      - linkedin_visit_profile
                      - linkedin_endorse_skills
                      - linkedin_withdraw_connection_request
                      - email_send
                      - wait
                      - wait_for_event
                      - condition
                      - api_call
                      - ask_ai
                      - manual_task
                      - linkedin_like_latest_post
                      - linkedin_comment_latest_post
                      - ab_test
                      - move_to_workflow
                      - add_tag
                      - remove_tag
                      - set_field
                      - change_sender
                      - run_column
              additionalProperties: false
              description: 'Manual queue = { eq: "manual_task" }.'
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - pending
                    - scheduled
                    - dispatched
                    - done
                    - failed
                    - skipped
                    - skipped_reply
                    - skipped_stoplisted
                    - cancelled
                    - expired
                ne:
                  type: string
                  enum:
                    - pending
                    - scheduled
                    - dispatched
                    - done
                    - failed
                    - skipped
                    - skipped_reply
                    - skipped_stoplisted
                    - cancelled
                    - expired
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
              additionalProperties: false
              description: Open = pending | scheduled | dispatched; the rest are terminal.
            assignee_user_sid:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: '"My manual tasks" scope (external user sid); is_null:true = unassigned team queue.'
            error_code:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Failure triage on failed | expired rows.
            scheduled_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: '"What dispatches in the next hour" - ISO 8601 bounds.'
            finished_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Executed-history window; is_null:true = still open.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Planning window, ISO 8601.
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - people
              - workflow_record
              - workflow
              - sender_profile
              - eta
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - scheduled_at
                - finished_at
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowTasksResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  workflow_sid:
                    type: string
                    nullable: true
                    description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
                  workflow_version_sid:
                    type: string
                    nullable: true
                    description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
                  workflow_record_sid:
                    type: string
                    nullable: true
                    description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
                  people_sid:
                    type: string
                    description: The person (cr_pp_…), denormalized for the person timeline.
                  step_id:
                    type: integer
                    nullable: true
                    description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
                  type:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                      - linkedin_send_message
                      - linkedin_send_inmail
                      - linkedin_visit_profile
                      - linkedin_endorse_skills
                      - linkedin_withdraw_connection_request
                      - email_send
                      - wait
                      - wait_for_event
                      - condition
                      - api_call
                      - ask_ai
                      - manual_task
                      - linkedin_like_latest_post
                      - linkedin_comment_latest_post
                      - ab_test
                      - move_to_workflow
                      - add_tag
                      - remove_tag
                      - set_field
                      - change_sender
                      - run_column
                    description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
                  attempt:
                    type: integer
                    description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
                  initiator:
                    type: string
                    enum:
                      - workflow_record
                      - play
                      - user
                    description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
                  play_sid:
                    type: string
                    nullable: true
                    description: The play that bore the task (pt_pl_…); null on a journey's task.
                  trigger_activity_sid:
                    type: string
                    nullable: true
                    description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
                  act:
                    type: object
                    nullable: true
                    properties:
                      do:
                        type: string
                        enum:
                          - send_message
                          - add_to_workflow
                          - like
                          - comment
                          - ask
                        description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                      about:
                        type: string
                        enum:
                          - birthday
                          - work_anniversary
                          - job_change
                          - post
                          - website_visit
                          - event
                        description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                      actor_sid:
                        type: string
                        description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                      target_workflow_sid:
                        type: string
                        description: add_to_workflow, and a question whose move or add names one.
                      post_urn:
                        type: string
                        description: "like, comment: the post the act goes to (an activity URN)."
                      reaction:
                        type: string
                        description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                      options:
                        type: array
                        items:
                          type: string
                          enum:
                            - remove
                            - keep
                            - move
                            - add
                        description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                      suggested:
                        type: string
                        enum:
                          - remove
                          - keep
                          - move
                          - add
                        description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
                    required:
                      - do
                      - about
                    description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
                  sender_profile_sid:
                    type: string
                    nullable: true
                    description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
                  assignee_user_sid:
                    type: string
                    nullable: true
                    description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
                  scheduled_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
                  timeout_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - stamped on scheduled → dispatched.
                  expires_at:
                    type: string
                    nullable: true
                    description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - stamped once on any terminal status.
                  variables_snapshot:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                    description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
                  error_code:
                    type: string
                    nullable: true
                    description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
                  error_message:
                    type: string
                    nullable: true
                    description: Human detail of the failure (max 1024); null on a skip.
                  previous_attempts:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        attempt:
                          type: integer
                          description: The attempt number it was.
                        status:
                          type: string
                          enum:
                            - pending
                            - scheduled
                            - dispatched
                            - done
                            - failed
                            - skipped
                            - skipped_reply
                            - skipped_stoplisted
                            - cancelled
                            - expired
                          description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                        error_code:
                          type: string
                          nullable: true
                          description: Its reason token.
                        error_message:
                          type: string
                          nullable: true
                        result:
                          type: object
                          nullable: true
                          additionalProperties: {}
                          description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                        dispatched_at:
                          type: string
                          nullable: true
                          description: ISO 8601 UTC.
                        finished_at:
                          type: string
                          nullable: true
                          description: ISO 8601 UTC.
                      required:
                        - attempt
                        - status
                        - error_code
                        - error_message
                        - result
                        - dispatched_at
                        - finished_at
                    description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
                  created_at:
                    type: string
                    description: ISO 8601 UTC - the planning moment.
                  updated_at:
                    type: string
                    description: ISO 8601 UTC.
                  deleted_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
                required:
                  - sid
                  - team_sid
                  - workflow_sid
                  - workflow_version_sid
                  - workflow_record_sid
                  - people_sid
                  - step_id
                  - type
                  - attempt
                  - status
                  - initiator
                  - play_sid
                  - trigger_activity_sid
                  - act
                  - sender_profile_sid
                  - assignee_user_sid
                  - scheduled_at
                  - timeout_at
                  - dispatched_at
                  - expires_at
                  - finished_at
                  - variables_snapshot
                  - result
                  - error_code
                  - error_message
                  - previous_attempts
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  people:
                    type: object
                    additionalProperties: {}
                    description: The person row (PeopleDomain - entities/people.md), 1:1.
                  workflow_record:
                    type: object
                    additionalProperties: {}
                    description: Owning record (WorkflowRecordDomain - entities/workflow_records.md), 1:1.
                  workflow:
                    type: object
                    additionalProperties: {}
                    description: Parent workflow (WorkflowDomain - entities/workflows.md), 1:1 - campaign name for queue cards.
                  sender_profile:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Sending identity (SenderProfileDomain - entities/sender_profiles.md), 1:1; null for orchestration-class tasks.
                  eta:
                    type: object
                    nullable: true
                    properties:
                      eta_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC. A send: the minute the sender profile pick is expected to hand it off, laid over the send window. A wait: when it will be decided, never before the timeout pass reads it again (a sync that is overdue backs off, up to a day). Null while the account does not sync at all, or the journey is paused."
                      position:
                        type: integer
                        nullable: true
                        description: "A send: 1-based position in its (sender profile, action type) bucket's order. A wait: null."
                      days_ahead:
                        type: integer
                        nullable: true
                        description: "A send: whole days of the bucket's cap ahead of it. A wait: calendar days from today (UTC)."
                      waits_for:
                        type: string
                        enum:
                          - deadline
                          - linkedin_sync
                          - journey
                          - send_outcome
                        description: "What the time waits for. A wait: linkedin_sync = an accept wait is decided on the account's first connections sync after the wait ends, which can be days later (2026-09-27). A send: send_outcome = gtm-api could not confirm whether the last attempt went out, and eta_at is the next time it is asked, not a send; it goes out again only on gtm's proof that it did not (2026-10-04)."
                      account_status:
                        type: string
                        nullable: true
                        enum:
                          - reconnect_required
                          - disconnected
                          - stopped
                        description: "A wait only: the sender profile's LinkedIn state when the account does not sync at all (eta_at is null then)."
                      journey_status:
                        type: string
                        enum:
                          - paused_on_reply
                          - paused_manual
                          - paused_blocked
                        description: "waits_for journey only: the pause that holds the wait."
                      expires_at:
                        type: string
                        nullable: true
                        description: "ISO 8601 UTC. waits_for linkedin_sync: when the wait fails (wait_expired, the journey with it) if its account never syncs its connections, 30 days past the wait's deadline. waits_for send_outcome: when the step fails send_unconfirmed for a person if gtm-api still cannot tell, a day after the doubt began. Null for every other task."
                    required:
                      - eta_at
                      - position
                      - days_ahead
                    description: "When a planned task is expected to run, computed on read: the sender profile scheduler's estimate for a scheduled send-class task (or, for a send in doubt, when gtm-api is asked again about its last attempt), and for a pending wait with a deadline when it will be decided (an accept wait after its account's connections sync past the deadline) or the pause that holds it. Null for every other task."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Tasks matching the filter (full filter scope, not the page).
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Execution funnel by WorkflowTaskStatusEnum (9 values).
                type:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Step-kind mix by WorkflowTaskTypeEnum (13 values).
                workflow_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Per-campaign task load, keyed by wf_wf_ sid.
                sender_profile_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Per-sender queue depth; the "null" bucket = orchestration-class.
                error_code:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: number
                    - type: array
                      items: {}
                  description: Failure triage ("what is breaking"), keyed by error_code or "null".
              required:
                - status
                - type
                - workflow_sid
                - sender_profile_sid
                - error_code
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowVersionsRequest:
      type: object
      description: Request body of `search_workflow_versions`.
      properties:
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_vr_
                  description: Workflow version sid (wf_vr_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_vr_
                    description: Workflow version sid (wf_vr_…).
              additionalProperties: false
              description: Version sid(s), wf_vr_ prefix (prefix-validated).
            workflow_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: Parent workflow sid (wf_wf_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Parent workflow sid (wf_wf_…).
              additionalProperties: false
              description: History scope - versions of one workflow (wf_wf_…).
            version:
              type: object
              properties:
                eq:
                  type: integer
                  minimum: 1
                gte:
                  type: integer
                  minimum: 1
                lte:
                  type: integer
                  minimum: 1
                gt:
                  type: integer
                  minimum: 1
                lt:
                  type: integer
                  minimum: 1
              additionalProperties: false
              description: Per-workflow sequence number ("versions after v5"); meaningful with a workflow_sid filter.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: Publish moment, ISO 8601 range ("what was live last week"); combine bounds in one object.
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - workflow
              - workflow_records_counts
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - version
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 100
          description: A version row carries the whole step tree, so a page is capped at 100 here (the platform default is 500).
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowVersionsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                    description: Version sid (wf_vr_…).
                  team_sid:
                    type: string
                    description: Owning team (ts_tm_…, external - gs.service.id).
                  workflow_sid:
                    type: string
                    description: Parent workflow (wf_wf_…) - written once at publish, never repointed; see ./workflows.md.
                  version:
                    type: integer
                    minimum: 1
                    description: Per-workflow sequence, max+1 at publish (serialized by the publish FOR UPDATE on the workflow row).
                  steps:
                    type: array
                    items:
                      oneOf:
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_send_connection_request
                            message:
                              type: string
                              nullable: true
                              description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                              description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                          required:
                            - id
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_send_message
                            message:
                              type: string
                              minLength: 1
                              maxLength: 8000
                              description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                              description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                          required:
                            - id
                            - type
                            - message
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_send_inmail
                            subject:
                              type: string
                              nullable: true
                              maxLength: 200
                              description: InMail subject template, max 200.
                            message:
                              type: string
                              minLength: 1
                              maxLength: 8000
                              description: InMail body template, 1..8000.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                              description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                          required:
                            - id
                            - type
                            - message
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_visit_profile
                          required:
                            - id
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_endorse_skills
                            skills_count:
                              type: integer
                              minimum: 1
                              maximum: 10
                              description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                          required:
                            - id
                            - type
                            - skills_count
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_withdraw_connection_request
                          required:
                            - id
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_like_latest_post
                          required:
                            - id
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - linkedin_comment_latest_post
                            comment:
                              type: string
                              minLength: 1
                              maxLength: 1250
                              description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                              description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                          required:
                            - id
                            - type
                            - comment
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - email_send
                            subject:
                              type: string
                              minLength: 1
                              maxLength: 255
                              description: Email subject template, 1..255.
                            body:
                              type: string
                              minLength: 1
                              maxLength: 100000
                              description: Email body template, HTML, 1..100000.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                              description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                            email_field:
                              type: string
                              nullable: true
                              description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                            cc:
                              type: array
                              nullable: true
                              items:
                                type: string
                                maxLength: 320
                                format: email
                              maxItems: 5
                              description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                            bcc:
                              type: array
                              nullable: true
                              items:
                                type: string
                                maxLength: 320
                                format: email
                              maxItems: 5
                              description: Up to 5 literal blind-copy addresses.
                            attachments:
                              type: array
                              nullable: true
                              items:
                                type: object
                                properties:
                                  sid:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^wf_at_
                                    description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                                  name:
                                    type: string
                                    minLength: 1
                                    maxLength: 255
                                    description: The filename the receiver sees.
                                required:
                                  - sid
                                  - name
                                additionalProperties: false
                              maxItems: 5
                              description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                            reply_in_thread:
                              type: boolean
                              nullable: true
                              description: True threads the send onto the prior email exchange.
                            track_opens:
                              type: boolean
                              nullable: true
                            track_clicks:
                              type: boolean
                              nullable: true
                            unsubscribe_link:
                              type: boolean
                              nullable: true
                          required:
                            - id
                            - type
                            - subject
                            - body
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            type:
                              type: string
                              enum:
                                - wait
                            for:
                              type: string
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                          required:
                            - id
                            - type
                            - for
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            type:
                              type: string
                              enum:
                                - wait_for_event
                            event:
                              type: string
                              enum:
                                - linkedin_connection_request_accepted
                                - email_opened
                                - email_link_clicked
                              description: Event a wait_for_event step blocks on (observed via activities ingest).
                            timeout:
                              type: object
                              properties:
                                after:
                                  type: string
                                  pattern: ^[1-9][0-9]*(m|h|d)$
                                  description: "Timeout duration - bundled: a timeout path cannot exist without one."
                                steps:
                                  type: array
                                  items:
                                    oneOf:
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_send_connection_request
                                          message:
                                            type: string
                                            nullable: true
                                            description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                                          required_fields:
                                            type: object
                                            nullable: true
                                            properties:
                                              refs:
                                                type: array
                                                items:
                                                  type: string
                                                  maxLength: 160
                                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                                maxItems: 20
                                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                              on_missing:
                                                type: string
                                                enum:
                                                  - fail
                                                  - skip
                                                description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                            required:
                                              - refs
                                              - on_missing
                                            additionalProperties: false
                                            description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_send_message
                                          message:
                                            type: string
                                            minLength: 1
                                            maxLength: 8000
                                            description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                                          required_fields:
                                            type: object
                                            nullable: true
                                            properties:
                                              refs:
                                                type: array
                                                items:
                                                  type: string
                                                  maxLength: 160
                                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                                maxItems: 20
                                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                              on_missing:
                                                type: string
                                                enum:
                                                  - fail
                                                  - skip
                                                description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                            required:
                                              - refs
                                              - on_missing
                                            additionalProperties: false
                                            description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                        required:
                                          - id
                                          - type
                                          - message
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_send_inmail
                                          subject:
                                            type: string
                                            nullable: true
                                            maxLength: 200
                                            description: InMail subject template, max 200.
                                          message:
                                            type: string
                                            minLength: 1
                                            maxLength: 8000
                                            description: InMail body template, 1..8000.
                                          required_fields:
                                            type: object
                                            nullable: true
                                            properties:
                                              refs:
                                                type: array
                                                items:
                                                  type: string
                                                  maxLength: 160
                                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                                maxItems: 20
                                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                              on_missing:
                                                type: string
                                                enum:
                                                  - fail
                                                  - skip
                                                description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                            required:
                                              - refs
                                              - on_missing
                                            additionalProperties: false
                                            description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                        required:
                                          - id
                                          - type
                                          - message
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_visit_profile
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_endorse_skills
                                          skills_count:
                                            type: integer
                                            minimum: 1
                                            maximum: 10
                                            description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                                        required:
                                          - id
                                          - type
                                          - skills_count
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_withdraw_connection_request
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_like_latest_post
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - linkedin_comment_latest_post
                                          comment:
                                            type: string
                                            minLength: 1
                                            maxLength: 1250
                                            description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                                          required_fields:
                                            type: object
                                            nullable: true
                                            properties:
                                              refs:
                                                type: array
                                                items:
                                                  type: string
                                                  maxLength: 160
                                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                                maxItems: 20
                                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                              on_missing:
                                                type: string
                                                enum:
                                                  - fail
                                                  - skip
                                                description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                            required:
                                              - refs
                                              - on_missing
                                            additionalProperties: false
                                            description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                                        required:
                                          - id
                                          - type
                                          - comment
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - email_send
                                          subject:
                                            type: string
                                            minLength: 1
                                            maxLength: 255
                                            description: Email subject template, 1..255.
                                          body:
                                            type: string
                                            minLength: 1
                                            maxLength: 100000
                                            description: Email body template, HTML, 1..100000.
                                          required_fields:
                                            type: object
                                            nullable: true
                                            properties:
                                              refs:
                                                type: array
                                                items:
                                                  type: string
                                                  maxLength: 160
                                                  pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                                maxItems: 20
                                                description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                              on_missing:
                                                type: string
                                                enum:
                                                  - fail
                                                  - skip
                                                description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                            required:
                                              - refs
                                              - on_missing
                                            additionalProperties: false
                                            description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                          email_field:
                                            type: string
                                            nullable: true
                                            description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                                          cc:
                                            type: array
                                            nullable: true
                                            items:
                                              type: string
                                              maxLength: 320
                                              format: email
                                            maxItems: 5
                                            description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                                          bcc:
                                            type: array
                                            nullable: true
                                            items:
                                              type: string
                                              maxLength: 320
                                              format: email
                                            maxItems: 5
                                            description: Up to 5 literal blind-copy addresses.
                                          attachments:
                                            type: array
                                            nullable: true
                                            items:
                                              type: object
                                              properties:
                                                sid:
                                                  type: string
                                                  minLength: 18
                                                  maxLength: 18
                                                  pattern: ^wf_at_
                                                  description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                                                name:
                                                  type: string
                                                  minLength: 1
                                                  maxLength: 255
                                                  description: The filename the receiver sees.
                                              required:
                                                - sid
                                                - name
                                              additionalProperties: false
                                            maxItems: 5
                                            description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                                          reply_in_thread:
                                            type: boolean
                                            nullable: true
                                            description: True threads the send onto the prior email exchange.
                                          track_opens:
                                            type: boolean
                                            nullable: true
                                          track_clicks:
                                            type: boolean
                                            nullable: true
                                          unsubscribe_link:
                                            type: boolean
                                            nullable: true
                                        required:
                                          - id
                                          - type
                                          - subject
                                          - body
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          type:
                                            type: string
                                            enum:
                                              - wait
                                          for:
                                            type: string
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                                        required:
                                          - id
                                          - type
                                          - for
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          type:
                                            type: string
                                            enum:
                                              - wait_for_event
                                          event:
                                            type: string
                                            enum:
                                              - linkedin_connection_request_accepted
                                              - email_opened
                                              - email_link_clicked
                                            description: Event a wait_for_event step blocks on (observed via activities ingest).
                                          timeout:
                                            type: object
                                            properties:
                                              after:
                                                type: string
                                                pattern: ^[1-9][0-9]*(m|h|d)$
                                                description: "Timeout duration - bundled: a timeout path cannot exist without one."
                                              steps:
                                                type: array
                                                items:
                                                  type: object
                                                  additionalProperties: {}
                                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                                description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                                            required:
                                              - after
                                              - steps
                                            additionalProperties: false
                                            description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                                        required:
                                          - id
                                          - type
                                          - event
                                          - timeout
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - condition
                                          branches:
                                            type: array
                                            items:
                                              type: object
                                              additionalProperties: {}
                                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                            minItems: 1
                                            maxItems: 9
                                            description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                                          else:
                                            type: array
                                            items:
                                              type: object
                                              additionalProperties: {}
                                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                            description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                                        required:
                                          - id
                                          - type
                                          - branches
                                          - else
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - ab_test
                                          branches:
                                            type: array
                                            items:
                                              type: object
                                              additionalProperties: {}
                                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                            minItems: 2
                                            maxItems: 9
                                            description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                                        required:
                                          - id
                                          - type
                                          - branches
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          type:
                                            type: string
                                            enum:
                                              - end
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - api_call
                                          method:
                                            type: string
                                            enum:
                                              - GET
                                              - POST
                                              - PUT
                                              - PATCH
                                              - DELETE
                                            description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                                          url:
                                            type: string
                                            minLength: 1
                                            maxLength: 2048
                                            description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                                          headers:
                                            type: object
                                            nullable: true
                                            additionalProperties:
                                              type: string
                                              maxLength: 1024
                                            description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                                          query:
                                            type: object
                                            nullable: true
                                            additionalProperties:
                                              type: string
                                              maxLength: 2048
                                            description: Up to 20 query parameters appended to the URL; values are templates.
                                          body:
                                            type: string
                                            nullable: true
                                            maxLength: 16000
                                            description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                                          provider_connection_sid:
                                            type: string
                                            nullable: true
                                            minLength: 18
                                            maxLength: 18
                                            pattern: ^in_cn_
                                            description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                                          timeout_secs:
                                            type: integer
                                            nullable: true
                                            minimum: 1
                                            maximum: 120
                                            description: The call budget in seconds; null = 15.
                                          retry_on_error:
                                            type: boolean
                                            nullable: true
                                            description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                                          remove_empty_values:
                                            type: boolean
                                            nullable: true
                                            description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                                          output_key:
                                            type: string
                                            nullable: true
                                            pattern: ^[a-z][a-z0-9_]{0,63}$
                                            description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                                        required:
                                          - id
                                          - type
                                          - method
                                          - url
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - ask_ai
                                          prompt:
                                            type: string
                                            minLength: 1
                                            maxLength: 8000
                                            description: Prompt template, 1..8000 - same variable namespaces as message templates.
                                          output_key:
                                            type: string
                                            pattern: ^[a-z][a-z0-9_]{0,63}$
                                            description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                                          preset_sid:
                                            type: string
                                            nullable: true
                                            description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                                        required:
                                          - id
                                          - type
                                          - prompt
                                          - output_key
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          type:
                                            type: string
                                            enum:
                                              - manual_task
                                          title:
                                            type: string
                                            minLength: 1
                                            maxLength: 255
                                            description: Todo title template, 1..255.
                                          instructions:
                                            type: string
                                            nullable: true
                                            maxLength: 4000
                                            description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                                        required:
                                          - id
                                          - type
                                          - title
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - move_to_workflow
                                          target_workflow_sid:
                                            type: string
                                            minLength: 18
                                            maxLength: 18
                                            pattern: ^wf_wf_
                                            description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                                          mode:
                                            type: string
                                            nullable: true
                                            enum:
                                              - from_start
                                              - from_current
                                            description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                                        required:
                                          - id
                                          - type
                                          - target_workflow_sid
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - add_tag
                                          tag_sids:
                                            type: array
                                            items:
                                              type: string
                                              minLength: 18
                                              maxLength: 18
                                              pattern: ^cr_tg_
                                              description: CRM tag sid (cr_tg_…).
                                            minItems: 1
                                            maxItems: 20
                                            description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                                        required:
                                          - id
                                          - type
                                          - tag_sids
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - remove_tag
                                          tag_sids:
                                            type: array
                                            items:
                                              type: string
                                              minLength: 18
                                              maxLength: 18
                                              pattern: ^cr_tg_
                                              description: CRM tag sid (cr_tg_…).
                                            minItems: 1
                                            maxItems: 20
                                            description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                                        required:
                                          - id
                                          - type
                                          - tag_sids
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - set_field
                                          field_slug:
                                            type: string
                                            pattern: ^[a-z][a-z0-9_]{0,63}$
                                            description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                                          value:
                                            anyOf:
                                              - type: string
                                              - type: number
                                              - type: boolean
                                              - {}
                                              - {}
                                            description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                                        required:
                                          - id
                                          - type
                                          - field_slug
                                          - value
                                        additionalProperties: false
                                      - type: object
                                        properties:
                                          id:
                                            type: integer
                                            minimum: 1
                                            description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                          name:
                                            type: string
                                            nullable: true
                                            maxLength: 255
                                            description: Editor label.
                                          delay:
                                            type: string
                                            nullable: true
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                          type:
                                            type: string
                                            enum:
                                              - change_sender
                                          sender_profile_sid:
                                            type: string
                                            nullable: true
                                            minLength: 18
                                            maxLength: 18
                                            pattern: ^ub_sp_
                                            description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                                          rotation:
                                            type: string
                                            nullable: true
                                            enum:
                                              - fair
                                              - random
                                              - new_sender
                                              - prior_engagement
                                            description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                                          rotations:
                                            type: array
                                            nullable: true
                                            items:
                                              type: object
                                              properties:
                                                sender_profile_sid:
                                                  type: string
                                                  nullable: true
                                                  minLength: 18
                                                  maxLength: 18
                                                  pattern: ^ub_sp_
                                                  description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                                                entry_step_id:
                                                  type: integer
                                                  nullable: true
                                                  minimum: 0
                                                  exclusiveMinimum: true
                                                  description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                                              required:
                                                - sender_profile_sid
                                                - entry_step_id
                                              additionalProperties: false
                                            minItems: 1
                                            maxItems: 10
                                            description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                                        required:
                                          - id
                                          - type
                                        additionalProperties: false
                                  description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                              required:
                                - after
                                - steps
                              additionalProperties: false
                              description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                          required:
                            - id
                            - type
                            - event
                            - timeout
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - condition
                            branches:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: integer
                                    minimum: 1
                                    description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                  label:
                                    type: string
                                    nullable: true
                                    maxLength: 255
                                    description: Editor caption.
                                  when:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                  steps:
                                    type: array
                                    items:
                                      type: object
                                      additionalProperties: {}
                                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                    description: Branch sub-flow; falls through to the condition's successor unless it ends with `end`.
                                required:
                                  - id
                                  - when
                                  - steps
                                additionalProperties: false
                              minItems: 1
                              maxItems: 9
                              description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                            else:
                              type: array
                              items:
                                oneOf:
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_send_connection_request
                                      message:
                                        type: string
                                        nullable: true
                                        description: "Invite note template; rendered note <=300 chars - enforced at publish after variable resolution (research: max 300 RENDERED). null/omitted = blank invite."
                                      required_fields:
                                        type: object
                                        nullable: true
                                        properties:
                                          refs:
                                            type: array
                                            items:
                                              type: string
                                              maxLength: 160
                                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                            maxItems: 20
                                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                          on_missing:
                                            type: string
                                            enum:
                                              - fail
                                              - skip
                                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                        required:
                                          - refs
                                          - on_missing
                                        additionalProperties: false
                                        description: "When a value the note needs is empty: refs required on top of the text + on_missing policy."
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_send_message
                                      message:
                                        type: string
                                        minLength: 1
                                        maxLength: 8000
                                        description: Message template ({{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}}); rendered at task time.
                                      required_fields:
                                        type: object
                                        nullable: true
                                        properties:
                                          refs:
                                            type: array
                                            items:
                                              type: string
                                              maxLength: 160
                                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                            maxItems: 20
                                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                          on_missing:
                                            type: string
                                            enum:
                                              - fail
                                              - skip
                                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                        required:
                                          - refs
                                          - on_missing
                                        additionalProperties: false
                                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                    required:
                                      - id
                                      - type
                                      - message
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_send_inmail
                                      subject:
                                        type: string
                                        nullable: true
                                        maxLength: 200
                                        description: InMail subject template, max 200.
                                      message:
                                        type: string
                                        minLength: 1
                                        maxLength: 8000
                                        description: InMail body template, 1..8000.
                                      required_fields:
                                        type: object
                                        nullable: true
                                        properties:
                                          refs:
                                            type: array
                                            items:
                                              type: string
                                              maxLength: 160
                                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                            maxItems: 20
                                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                          on_missing:
                                            type: string
                                            enum:
                                              - fail
                                              - skip
                                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                        required:
                                          - refs
                                          - on_missing
                                        additionalProperties: false
                                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                    required:
                                      - id
                                      - type
                                      - message
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_visit_profile
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_endorse_skills
                                      skills_count:
                                        type: integer
                                        minimum: 1
                                        maximum: 10
                                        description: Endorse the person's top N listed skills, 1..10 (named-skill targeting deferred - count-only in v1).
                                    required:
                                      - id
                                      - type
                                      - skills_count
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_withdraw_connection_request
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_like_latest_post
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - linkedin_comment_latest_post
                                      comment:
                                        type: string
                                        minLength: 1
                                        maxLength: 1250
                                        description: Comment template posted on the person's latest post, 1..1250 rendered; same variable namespaces as message templates.
                                      required_fields:
                                        type: object
                                        nullable: true
                                        properties:
                                          refs:
                                            type: array
                                            items:
                                              type: string
                                              maxLength: 160
                                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                            maxItems: 20
                                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                          on_missing:
                                            type: string
                                            enum:
                                              - fail
                                              - skip
                                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                        required:
                                          - refs
                                          - on_missing
                                        additionalProperties: false
                                        description: "When a value the comment needs is empty: refs required on top of the text + on_missing policy."
                                    required:
                                      - id
                                      - type
                                      - comment
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - email_send
                                      subject:
                                        type: string
                                        minLength: 1
                                        maxLength: 255
                                        description: Email subject template, 1..255.
                                      body:
                                        type: string
                                        minLength: 1
                                        maxLength: 100000
                                        description: Email body template, HTML, 1..100000.
                                      required_fields:
                                        type: object
                                        nullable: true
                                        properties:
                                          refs:
                                            type: array
                                            items:
                                              type: string
                                              maxLength: 160
                                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                            maxItems: 20
                                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>); every variable the text carries without a |fallback is required by itself. Slug existence resolved at RUNTIME per record's playtable, not at publish.
                                          on_missing:
                                            type: string
                                            enum:
                                              - fail
                                              - skip
                                            description: "Policy when a value the step text needs is empty at task time: fail = the task fails at once (required_fields_missing), the record with it, visible as Failed and run again through the task retry once the value is there; skip = skip this step and advance. A variable with a |fallback is never missing; no policy (null) = the text goes as it renders. The wait policy went on 2026-10-11."
                                        required:
                                          - refs
                                          - on_missing
                                        additionalProperties: false
                                        description: "When a value the text needs is empty: refs required on top of the text + on_missing policy."
                                      email_field:
                                        type: string
                                        nullable: true
                                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                                      cc:
                                        type: array
                                        nullable: true
                                        items:
                                          type: string
                                          maxLength: 320
                                          format: email
                                        maxItems: 5
                                        description: "Up to 5 literal copy addresses (no templates: a copy goes to a colleague)."
                                      bcc:
                                        type: array
                                        nullable: true
                                        items:
                                          type: string
                                          maxLength: 320
                                          format: email
                                        maxItems: 5
                                        description: Up to 5 literal blind-copy addresses.
                                      attachments:
                                        type: array
                                        nullable: true
                                        items:
                                          type: object
                                          properties:
                                            sid:
                                              type: string
                                              minLength: 18
                                              maxLength: 18
                                              pattern: ^wf_at_
                                              description: A workflow attachment the team uploaded (create_workflow_attachment_upload_url).
                                            name:
                                              type: string
                                              minLength: 1
                                              maxLength: 255
                                              description: The filename the receiver sees.
                                          required:
                                            - sid
                                            - name
                                          additionalProperties: false
                                        maxItems: 5
                                        description: Up to 5 library files sent with the email; the executor reads the bytes at send time.
                                      reply_in_thread:
                                        type: boolean
                                        nullable: true
                                        description: True threads the send onto the prior email exchange.
                                      track_opens:
                                        type: boolean
                                        nullable: true
                                      track_clicks:
                                        type: boolean
                                        nullable: true
                                      unsubscribe_link:
                                        type: boolean
                                        nullable: true
                                    required:
                                      - id
                                      - type
                                      - subject
                                      - body
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      type:
                                        type: string
                                        enum:
                                          - wait
                                      for:
                                        type: string
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: How long to pause the record before the next step - "45m" / "12h" / "14d" (replaces v3 timer.duration_seconds).
                                    required:
                                      - id
                                      - type
                                      - for
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      type:
                                        type: string
                                        enum:
                                          - wait_for_event
                                      event:
                                        type: string
                                        enum:
                                          - linkedin_connection_request_accepted
                                          - email_opened
                                          - email_link_clicked
                                        description: Event a wait_for_event step blocks on (observed via activities ingest).
                                      timeout:
                                        type: object
                                        properties:
                                          after:
                                            type: string
                                            pattern: ^[1-9][0-9]*(m|h|d)$
                                            description: "Timeout duration - bundled: a timeout path cannot exist without one."
                                          steps:
                                            type: array
                                            items:
                                              type: object
                                              additionalProperties: {}
                                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                            description: Fallback sub-flow; [] = on timeout, continue as if the event fired; falls through to the parent chain unless it ends with `end`.
                                        required:
                                          - after
                                          - steps
                                        additionalProperties: false
                                        description: "Required since 2026-10-11: a wait always has a time limit (a wait with no end is a stuck journey); steps: [] = on timeout, continue as if the event fired. The reply-pause machinery still applies (KNOWLEDGE §4.9)."
                                    required:
                                      - id
                                      - type
                                      - event
                                      - timeout
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - condition
                                      branches:
                                        type: array
                                        items:
                                          type: object
                                          additionalProperties: {}
                                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                        minItems: 1
                                        maxItems: 9
                                        description: 1..9, evaluated in order, first match wins; the fired branch id lands on the condition task result (workflow_tasks.md).
                                      else:
                                        type: array
                                        items:
                                          type: object
                                          additionalProperties: {}
                                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                        description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                                    required:
                                      - id
                                      - type
                                      - branches
                                      - else
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - ab_test
                                      branches:
                                        type: array
                                        items:
                                          type: object
                                          additionalProperties: {}
                                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                        minItems: 2
                                        maxItems: 9
                                        description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                                    required:
                                      - id
                                      - type
                                      - branches
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      type:
                                        type: string
                                        enum:
                                          - end
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - api_call
                                      method:
                                        type: string
                                        enum:
                                          - GET
                                          - POST
                                          - PUT
                                          - PATCH
                                          - DELETE
                                        description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                                      url:
                                        type: string
                                        minLength: 1
                                        maxLength: 2048
                                        description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                                      headers:
                                        type: object
                                        nullable: true
                                        additionalProperties:
                                          type: string
                                          maxLength: 1024
                                        description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                                      query:
                                        type: object
                                        nullable: true
                                        additionalProperties:
                                          type: string
                                          maxLength: 2048
                                        description: Up to 20 query parameters appended to the URL; values are templates.
                                      body:
                                        type: string
                                        nullable: true
                                        maxLength: 16000
                                        description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                                      provider_connection_sid:
                                        type: string
                                        nullable: true
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^in_cn_
                                        description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                                      timeout_secs:
                                        type: integer
                                        nullable: true
                                        minimum: 1
                                        maximum: 120
                                        description: The call budget in seconds; null = 15.
                                      retry_on_error:
                                        type: boolean
                                        nullable: true
                                        description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                                      remove_empty_values:
                                        type: boolean
                                        nullable: true
                                        description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                                      output_key:
                                        type: string
                                        nullable: true
                                        pattern: ^[a-z][a-z0-9_]{0,63}$
                                        description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                                    required:
                                      - id
                                      - type
                                      - method
                                      - url
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - ask_ai
                                      prompt:
                                        type: string
                                        minLength: 1
                                        maxLength: 8000
                                        description: Prompt template, 1..8000 - same variable namespaces as message templates.
                                      output_key:
                                        type: string
                                        pattern: ^[a-z][a-z0-9_]{0,63}$
                                        description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                                      preset_sid:
                                        type: string
                                        nullable: true
                                        description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                                    required:
                                      - id
                                      - type
                                      - prompt
                                      - output_key
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      type:
                                        type: string
                                        enum:
                                          - manual_task
                                      title:
                                        type: string
                                        minLength: 1
                                        maxLength: 255
                                        description: Todo title template, 1..255.
                                      instructions:
                                        type: string
                                        nullable: true
                                        maxLength: 4000
                                        description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                                    required:
                                      - id
                                      - type
                                      - title
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - move_to_workflow
                                      target_workflow_sid:
                                        type: string
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^wf_wf_
                                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                                      mode:
                                        type: string
                                        nullable: true
                                        enum:
                                          - from_start
                                          - from_current
                                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                                    required:
                                      - id
                                      - type
                                      - target_workflow_sid
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - add_tag
                                      tag_sids:
                                        type: array
                                        items:
                                          type: string
                                          minLength: 18
                                          maxLength: 18
                                          pattern: ^cr_tg_
                                          description: CRM tag sid (cr_tg_…).
                                        minItems: 1
                                        maxItems: 20
                                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                                    required:
                                      - id
                                      - type
                                      - tag_sids
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - remove_tag
                                      tag_sids:
                                        type: array
                                        items:
                                          type: string
                                          minLength: 18
                                          maxLength: 18
                                          pattern: ^cr_tg_
                                          description: CRM tag sid (cr_tg_…).
                                        minItems: 1
                                        maxItems: 20
                                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                                    required:
                                      - id
                                      - type
                                      - tag_sids
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - set_field
                                      field_slug:
                                        type: string
                                        pattern: ^[a-z][a-z0-9_]{0,63}$
                                        description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                                      value:
                                        anyOf:
                                          - type: string
                                          - type: number
                                          - type: boolean
                                          - {}
                                          - {}
                                        description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                                    required:
                                      - id
                                      - type
                                      - field_slug
                                      - value
                                    additionalProperties: false
                                  - type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                      name:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor label.
                                      delay:
                                        type: string
                                        nullable: true
                                        pattern: ^[1-9][0-9]*(m|h|d)$
                                        description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                                      type:
                                        type: string
                                        enum:
                                          - change_sender
                                      sender_profile_sid:
                                        type: string
                                        nullable: true
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^ub_sp_
                                        description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                                      rotation:
                                        type: string
                                        nullable: true
                                        enum:
                                          - fair
                                          - random
                                          - new_sender
                                          - prior_engagement
                                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                                      rotations:
                                        type: array
                                        nullable: true
                                        items:
                                          type: object
                                          properties:
                                            sender_profile_sid:
                                              type: string
                                              nullable: true
                                              minLength: 18
                                              maxLength: 18
                                              pattern: ^ub_sp_
                                              description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                                            entry_step_id:
                                              type: integer
                                              nullable: true
                                              minimum: 0
                                              exclusiveMinimum: true
                                              description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                                          required:
                                            - sender_profile_sid
                                            - entry_step_id
                                          additionalProperties: false
                                        minItems: 1
                                        maxItems: 10
                                        description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                                    required:
                                      - id
                                      - type
                                    additionalProperties: false
                              description: REQUIRED no-match path (may be []); falls through unless it ends with `end`.
                          required:
                            - id
                            - type
                            - branches
                            - else
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - ab_test
                            branches:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: integer
                                    minimum: 1
                                    description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                                  label:
                                    type: string
                                    nullable: true
                                    maxLength: 255
                                    description: Editor caption ("Variant A").
                                  weight:
                                    type: integer
                                    minimum: 1
                                    description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights), first arm whose cumulative range contains it (workflow_versions.md ab_test algorithm).
                                  steps:
                                    type: array
                                    items:
                                      type: object
                                      additionalProperties: {}
                                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                    description: Arm sub-flow; falls through to the ab_test successor unless it ends with `end`.
                                required:
                                  - id
                                  - weight
                                  - steps
                                additionalProperties: false
                              minItems: 2
                              maxItems: 9
                              description: 2..9 weighted arms; the record is assigned to one deterministically by hashing its sid into the weight distribution (workflow_versions.md). No `else` - weights cover the whole distribution.
                          required:
                            - id
                            - type
                            - branches
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            type:
                              type: string
                              enum:
                                - end
                          required:
                            - id
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - api_call
                            method:
                              type: string
                              enum:
                                - GET
                                - POST
                                - PUT
                                - PATCH
                                - DELETE
                              description: The request method. POST / PUT / PATCH carry the JSON body; GET / DELETE must publish with body null.
                            url:
                              type: string
                              minLength: 1
                              maxLength: 2048
                              description: "https-only (publish check), max 2048. A template: {{people.*}} / {{company.*}} / {{record.<slug>}} / {{ai.<key>}} may stand in the path and the query and are URL-encoded where they stand."
                            headers:
                              type: object
                              nullable: true
                              additionalProperties:
                                type: string
                                maxLength: 1024
                              description: Up to 20 custom request headers; values are templates. Auth comes from provider_connection_sid, never from a literal here.
                            query:
                              type: object
                              nullable: true
                              additionalProperties:
                                type: string
                                maxLength: 2048
                              description: Up to 20 query parameters appended to the URL; values are templates.
                            body:
                              type: string
                              nullable: true
                              maxLength: 16000
                              description: A JSON body template with the variables INSIDE quotes ("{{people.full_name}}"), stood in JSON-safely at call time. null = the fixed payload {event, workflow_sid, workflow_record_sid, workflow_task_sid, step_id, people_sid, context}.
                            provider_connection_sid:
                              type: string
                              nullable: true
                              minLength: 18
                              maxLength: 18
                              pattern: ^in_cn_
                              description: "A `custom` provider connection of the team (provider-connections.search filter provider=custom): the integration platform injects its auth (bearer / basic / header / query) when the call fires. null = no auth (a public API)."
                            timeout_secs:
                              type: integer
                              nullable: true
                              minimum: 1
                              maximum: 120
                              description: The call budget in seconds; null = 15.
                            retry_on_error:
                              type: boolean
                              nullable: true
                              description: "null/true: a 5xx, a 429, a timeout or an unreachable target earns a fresh attempt (3 in all, with backoff); false: the record fails on the first error. A 4xx / auth refusal never retries."
                            remove_empty_values:
                              type: boolean
                              nullable: true
                              description: "true: empty rendered values leave the query and the body, so they never overwrite the receiver's data; null/false: sent as empty strings."
                            output_key:
                              type: string
                              nullable: true
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: "The answer's name for the steps after this one (2026-10-11): a slug, unique within the version together with the ask_ai keys (publish check). Later steps read {{api.<output_key>.<path>}} (a dotted path into the decoded JSON answer) and condition leaves filter on api.<output_key>.<path>; the answer is kept on the done task row, capped at 64 KB. null = the answer is not kept."
                          required:
                            - id
                            - type
                            - method
                            - url
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - ask_ai
                            prompt:
                              type: string
                              minLength: 1
                              maxLength: 8000
                              description: Prompt template, 1..8000 - same variable namespaces as message templates.
                            output_key:
                              type: string
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: Slug 1..64, unique within the version (publish check); later steps read {{ai.<output_key>}} and condition leaves filter on ai.<output_key>. Outputs live on the completed task row, never on records.
                            preset_sid:
                              type: string
                              nullable: true
                              description: gtm-api preset for the AI call (external sid, opaque); null/omitted = team default (service KNOWLEDGE §1).
                          required:
                            - id
                            - type
                            - prompt
                            - output_key
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            type:
                              type: string
                              enum:
                                - manual_task
                            title:
                              type: string
                              minLength: 1
                              maxLength: 255
                              description: Todo title template, 1..255.
                            instructions:
                              type: string
                              nullable: true
                              maxLength: 4000
                              description: Rendered into the human todo, max 4000; the journey waits until the task is completed (workflow_tasks.md manual queue).
                          required:
                            - id
                            - type
                            - title
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - move_to_workflow
                            target_workflow_sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_wf_
                              description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy (workflow_records.md). THIS record then completes - terminal-for-this-record.
                            mode:
                              type: string
                              nullable: true
                              enum:
                                - from_start
                                - from_current
                              description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                          required:
                            - id
                            - type
                            - target_workflow_sid
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - add_tag
                            tag_sids:
                              type: array
                              items:
                                type: string
                                minLength: 18
                                maxLength: 18
                                pattern: ^cr_tg_
                                description: CRM tag sid (cr_tg_…).
                              minItems: 1
                              maxItems: 20
                              description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through (tags.md).
                          required:
                            - id
                            - type
                            - tag_sids
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - remove_tag
                            tag_sids:
                              type: array
                              items:
                                type: string
                                minLength: 18
                                maxLength: 18
                                pattern: ^cr_tg_
                                description: CRM tag sid (cr_tg_…).
                              minItems: 1
                              maxItems: 20
                              description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                          required:
                            - id
                            - type
                            - tag_sids
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - set_field
                            field_slug:
                              type: string
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: Playtable field slug to write (pipeline_stage is a scalar_select field - service KNOWLEDGE §3).
                            value:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                                - {}
                                - {}
                              description: Scalar cell value written for the person (one cell; no arrays/objects); null clears the field (playtable_field_values.md).
                          required:
                            - id
                            - type
                            - field_slug
                            - value
                          additionalProperties: false
                        - type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned small int, unique across the whole document (steps + branch ids); immutable, never reused; user-facing in the editor tree.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            delay:
                              type: string
                              nullable: true
                              pattern: ^[1-9][0-9]*(m|h|d)$
                              description: 'How long the record waits at this step before it runs: "45m" / "12h" / "2d"; null/omitted = runs as soon as it arrives. Not allowed on wait (use `for`), wait_for_event, manual_task, end.'
                            type:
                              type: string
                              enum:
                                - change_sender
                            sender_profile_sid:
                              type: string
                              nullable: true
                              minLength: 18
                              maxLength: 18
                              pattern: ^ub_sp_
                              description: Explicit forward-only re-pin of workflow_records.sender_profile_sid (ub_sp_…). Exactly one of the three shapes (publish check).
                            rotation:
                              type: string
                              nullable: true
                              enum:
                                - fair
                                - random
                                - new_sender
                                - prior_engagement
                              description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid, forward only. Exactly one of the three shapes (publish check).
                            rotations:
                              type: array
                              nullable: true
                              items:
                                type: object
                                properties:
                                  sender_profile_sid:
                                    type: string
                                    nullable: true
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^ub_sp_
                                    description: The sender profile for this pass; null = the workflow's rotation strategy picks, never the sender profile the record already has. Must be in the workflow's pool (publish check).
                                  entry_step_id:
                                    type: integer
                                    nullable: true
                                    minimum: 0
                                    exclusiveMinimum: true
                                    description: A step id of THIS document to restart the journey from (publish check); null = the workflow's entry step.
                                required:
                                  - sender_profile_sid
                                  - entry_step_id
                                additionalProperties: false
                              minItems: 1
                              maxItems: 10
                              description: "The legacy gs_rotate_sender_profile list (D45): each pass through the node consumes the next entry and RESTARTS the journey from its entry step with its sender profile (touches start over; workflow_records.rotations_done is the cursor); past the end the journey continues. Exactly one of the three shapes (publish check)."
                          required:
                            - id
                            - type
                          additionalProperties: false
                    minItems: 1
                    maxItems: 100
                    description: "Immutable chain-and-blocks snapshot: array order = execution order, entry = steps[0], root-array exhaustion completes the record; 1..100 steps TOTAL incl. nested, <=512 KB serialized. Step ids are stable across versions."
                  steps_count:
                    type: integer
                    minimum: 1
                    maximum: 100
                    description: Denormalized total step count (incl. nested) at insert - lets lists/events skip the JSON.
                  entry_step_id:
                    type: integer
                    minimum: 1
                    description: = steps[0].id, denormalized at publish; every enrollment starts here.
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                    description: The PUBLISHER - actor of workflows.publish; answers "who shipped v7".
                  created_at:
                    type: string
                    description: "ISO 8601 UTC - the publish moment. No updated_at: the row never changes."
                required:
                  - sid
                  - team_sid
                  - workflow_sid
                  - version
                  - steps
                  - steps_count
                  - entry_step_id
                  - created_by
                  - created_at
              included:
                type: object
                properties:
                  workflow:
                    type: object
                    properties:
                      sid:
                        type: string
                      name:
                        type: string
                      status:
                        type: string
                      published_version_sid:
                        type: string
                        nullable: true
                    required:
                      - sid
                      - name
                      - status
                      - published_version_sid
                    description: "Parent workflow (WorkflowDomain - entities/workflows.md): name/status + published_version_sid to check whether THIS row is the live pointer."
                  workflow_records_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                        description: Records pinned to this version.
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: integer
                                  minimum: 0
                              - type: array
                                items: {}
                            description: Funnel by WorkflowRecordStatusEnum - non-terminal buckets = "who is still running this version".
                        required:
                          - status
                        description: Axes per WorkflowRecordGroupableFieldsEnum (canonical shape - entities/workflow_records.md). PHP empty map serialises as [].
                    required:
                      - total_count
                      - groups
                    description: "Parent-include counts (§4.17) computed against {workflow_version_sid: parent.sid}: how many records are pinned to this version and in which statuses, without loading rows."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Versions matching the filter - full filter scope, not the page.
            groups:
              type: object
              properties:
                workflow_sid:
                  anyOf:
                    - type: object
                      additionalProperties:
                        type: integer
                        minimum: 0
                    - type: array
                      items: {}
                  description: "Flat {wf_wf_ sid: version count} - versions-per-workflow distribution; backed by (team_sid, workflow_sid, version DESC)."
              required:
                - workflow_sid
              description: One axis per WorkflowVersionGroupableFieldsEnum value (§4.17). PHP empty map serialises as [].
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SearchWorkflowsRequest:
      type: object
      description: Request body of `search_workflows`.
      properties:
        filter:
          type: object
          properties:
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: The home playtable.
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: Workflow sid (wf_wf_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Workflow sid (wf_wf_…).
              additionalProperties: false
              description: Prefix-validated wf_wf_ sid(s).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - archived
                ne:
                  type: string
                  enum:
                    - draft
                    - active
                    - paused
                    - archived
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - archived
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - archived
              additionalProperties: false
              description: Default UI scope excludes archived client-side.
            published_version_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_vr_
                is_null:
                  type: boolean
              additionalProperties: false
              description: is_null:true = never published.
            agent_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_ag_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_ag_
                is_null:
                  type: boolean
              additionalProperties: false
              description: The AI SDR the workflow picked (ub_ag_…); is_null:true = the workflows on their table's pick.
            q:
              type: string
              maxLength: 128
              description: Free text over name + description (MySQL LIKE, prefix/infix).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: '"Recently edited" scans; ISO 8601 range.'
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row."
        include:
          type: array
          items:
            type: string
            enum:
              - published_version
              - sources
              - records_counts
              - step_stats
              - forecast
          description: Relations to attach to every item; omit for the bare rows.
        sort:
          type: object
          properties:
            field:
              type: string
              enum:
                - created_at
                - updated_at
                - name
              description: The column to order by.
            direction:
              type: string
              enum:
                - asc
                - desc
              description: asc or desc; default desc.
          required:
            - field
          description: One column and its direction; omit for the default order.
        page_size:
          type: integer
          minimum: 0
          maximum: 500
          description: 0..500, default 50; 0 = counts only, 1 = the first row.
        cursor:
          type: string
          nullable: true
          description: pagination.next_cursor of the previous page.
    SearchWorkflowsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - search
        items:
          type: array
          items:
            type: object
            properties:
              item:
                type: object
                properties:
                  sid:
                    type: string
                  team_sid:
                    type: string
                  name:
                    type: string
                  description:
                    type: string
                    nullable: true
                  status:
                    type: string
                    enum:
                      - draft
                      - active
                      - paused
                      - archived
                  published_version_sid:
                    type: string
                    nullable: true
                    description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
                  draft_steps:
                    type: array
                    items:
                      oneOf:
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_send_connection_request
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            message:
                              type: string
                              nullable: true
                              description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                          required:
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_send_message
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            message:
                              type: string
                              minLength: 1
                              maxLength: 8000
                              description: Message template (same namespaces as all templates).
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                          required:
                            - type
                            - message
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_send_inmail
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            subject:
                              type: string
                              nullable: true
                              maxLength: 200
                            message:
                              type: string
                              minLength: 1
                              maxLength: 8000
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                          required:
                            - type
                            - message
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_visit_profile
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                          required:
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_endorse_skills
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            skills_count:
                              type: integer
                              minimum: 1
                              maximum: 10
                              description: Endorse the person's top N listed skills, 1..10.
                          required:
                            - type
                            - skills_count
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_withdraw_connection_request
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                          required:
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_like_latest_post
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                          required:
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - linkedin_comment_latest_post
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            comment:
                              type: string
                              minLength: 1
                              maxLength: 1250
                              description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                          required:
                            - type
                            - comment
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - email_send
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            subject:
                              type: string
                              minLength: 1
                              maxLength: 255
                            body:
                              type: string
                              minLength: 1
                              maxLength: 100000
                              description: HTML body template.
                            required_fields:
                              type: object
                              nullable: true
                              properties:
                                refs:
                                  type: array
                                  items:
                                    type: string
                                    maxLength: 160
                                    pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                  maxItems: 20
                                  description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                on_missing:
                                  type: string
                                  enum:
                                    - fail
                                    - skip
                                  description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                              required:
                                - refs
                                - on_missing
                              additionalProperties: false
                            email_field:
                              type: string
                              nullable: true
                              description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                            cc:
                              type: array
                              nullable: true
                              items:
                                type: string
                                maxLength: 320
                                format: email
                              maxItems: 5
                              description: Up to 5 literal copy addresses.
                            bcc:
                              type: array
                              nullable: true
                              items:
                                type: string
                                maxLength: 320
                                format: email
                              maxItems: 5
                              description: Up to 5 literal blind-copy addresses.
                            attachments:
                              type: array
                              nullable: true
                              items:
                                type: object
                                properties:
                                  sid:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^wf_at_
                                  name:
                                    type: string
                                    minLength: 1
                                    maxLength: 255
                                required:
                                  - sid
                                  - name
                                additionalProperties: false
                              maxItems: 5
                              description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                            reply_in_thread:
                              type: boolean
                              nullable: true
                            track_opens:
                              type: boolean
                              nullable: true
                            track_clicks:
                              type: boolean
                              nullable: true
                            unsubscribe_link:
                              type: boolean
                              nullable: true
                          required:
                            - type
                            - subject
                            - body
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - wait
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            for:
                              type: string
                              pattern: ^[1-9][0-9]*[mhd]$
                              description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          required:
                            - type
                            - for
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - wait_for_event
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            event:
                              type: string
                              enum:
                                - linkedin_connection_request_accepted
                                - email_opened
                                - email_link_clicked
                              description: Event observed via the activities ingest.
                            timeout:
                              type: object
                              properties:
                                after:
                                  type: string
                                  pattern: ^[1-9][0-9]*[mhd]$
                                  description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                                steps:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - after
                                - steps
                              additionalProperties: false
                              description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                          required:
                            - type
                            - event
                            - timeout
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - condition
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            branches:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: integer
                                    minimum: 1
                                    description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                                  label:
                                    type: string
                                    nullable: true
                                    maxLength: 255
                                    description: Editor caption.
                                  when:
                                    type: object
                                    additionalProperties: {}
                                    description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                                  steps:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                required:
                                  - when
                                  - steps
                                additionalProperties: false
                              minItems: 1
                              maxItems: 9
                              description: 1..9 branches, evaluated in order, first match wins.
                            else:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - type
                            - branches
                            - else
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - ab_test
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            branches:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: integer
                                    minimum: 1
                                    description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                                  label:
                                    type: string
                                    nullable: true
                                    maxLength: 255
                                    description: Editor caption ("Variant A").
                                  weight:
                                    type: integer
                                    minimum: 1
                                    description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                                  steps:
                                    type: object
                                    additionalProperties: {}
                                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                required:
                                  - weight
                                  - steps
                                additionalProperties: false
                              minItems: 2
                              maxItems: 9
                              description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                          required:
                            - type
                            - branches
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - end
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                          required:
                            - type
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - api_call
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            method:
                              type: string
                              enum:
                                - GET
                                - POST
                                - PUT
                                - PATCH
                                - DELETE
                            url:
                              type: string
                              minLength: 1
                              maxLength: 2048
                              description: https-only (publish check); a template - variables may stand in the path and the query.
                            headers:
                              type: object
                              nullable: true
                              additionalProperties:
                                type: string
                                maxLength: 1024
                            query:
                              type: object
                              nullable: true
                              additionalProperties:
                                type: string
                                maxLength: 2048
                            body:
                              type: string
                              nullable: true
                              maxLength: 16000
                              description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                            provider_connection_sid:
                              type: string
                              nullable: true
                              minLength: 18
                              maxLength: 18
                              pattern: ^in_cn_
                              description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                            timeout_secs:
                              type: integer
                              nullable: true
                              minimum: 1
                              maximum: 120
                            retry_on_error:
                              type: boolean
                              nullable: true
                            remove_empty_values:
                              type: boolean
                              nullable: true
                            output_key:
                              type: string
                              nullable: true
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                          required:
                            - type
                            - method
                            - url
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - ask_ai
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            prompt:
                              type: string
                              minLength: 1
                              maxLength: 8000
                              description: Same variable namespaces as message templates.
                            output_key:
                              type: string
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                            preset_sid:
                              type: string
                              nullable: true
                              description: gtm-api preset for the AI call; null = team default.
                          required:
                            - type
                            - prompt
                            - output_key
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - manual_task
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            title:
                              type: string
                              minLength: 1
                              maxLength: 255
                            instructions:
                              type: string
                              nullable: true
                              maxLength: 4000
                              description: Rendered into the human todo; the journey waits until the task is completed.
                          required:
                            - type
                            - title
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - move_to_workflow
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            target_workflow_sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_wf_
                              description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                            mode:
                              type: string
                              nullable: true
                              enum:
                                - from_start
                                - from_current
                              description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                          required:
                            - type
                            - target_workflow_sid
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - add_tag
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            tag_sids:
                              type: array
                              items:
                                type: string
                                minLength: 18
                                maxLength: 18
                                pattern: ^cr_tg_
                              minItems: 1
                              maxItems: 20
                              description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                          required:
                            - type
                            - tag_sids
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - remove_tag
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            tag_sids:
                              type: array
                              items:
                                type: string
                                minLength: 18
                                maxLength: 18
                                pattern: ^cr_tg_
                              minItems: 1
                              maxItems: 20
                              description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                          required:
                            - type
                            - tag_sids
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - set_field
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            field_slug:
                              type: string
                              pattern: ^[a-z][a-z0-9_]{0,63}$
                              description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                            value:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                                - {}
                                - {}
                              description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                          required:
                            - type
                            - field_slug
                            - value
                          additionalProperties: false
                        - type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - change_sender
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                            name:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor label.
                            sender_profile_sid:
                              type: string
                              nullable: true
                              minLength: 18
                              maxLength: 18
                              pattern: ^ub_sp_
                              description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                            rotation:
                              type: string
                              nullable: true
                              enum:
                                - fair
                                - random
                                - new_sender
                                - prior_engagement
                              description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                          required:
                            - type
                          additionalProperties: false
                    description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
                  schedule:
                    type: object
                    nullable: true
                    properties:
                      timeblocks:
                        type: array
                        items:
                          type: object
                          properties:
                            dow:
                              type: integer
                              minimum: 0
                              maximum: 6
                              description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                            start_minute:
                              type: integer
                              minimum: 0
                              maximum: 1439
                              description: "Minutes from local midnight (legacy key: min)."
                            end_minute:
                              type: integer
                              minimum: 1
                              maximum: 1440
                              description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                          required:
                            - dow
                            - start_minute
                            - end_minute
                          additionalProperties: false
                      timezone:
                        type: string
                        description: IANA tz name - base timezone for the blocks.
                      use_people_timezone:
                        type: boolean
                        description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
                    required:
                      - timeblocks
                      - timezone
                      - use_people_timezone
                    description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
                  on_reply:
                    type: string
                    enum:
                      - autopilot
                      - copilot
                      - stop
                      - continue
                    description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
                  agent_sid:
                    type: string
                    nullable: true
                    description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
                  sender_profile_sids:
                    type: array
                    items:
                      type: string
                    description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
                  rotation_strategy:
                    type: string
                    enum:
                      - fair
                      - random
                      - new_sender
                      - prior_engagement
                  priority:
                    type: integer
                    description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
                  created_by:
                    type: object
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  deleted_by:
                    type: object
                    nullable: true
                    properties:
                      actor_type:
                        type: string
                        enum:
                          - user
                          - support
                          - api_key
                          - system
                          - agent
                      actor_sid:
                        type: string
                        nullable: true
                      team_sid:
                        type: string
                      actor_name:
                        type: string
                        nullable: true
                        description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                      oauth_client_sid:
                        type: string
                        nullable: true
                        description: The acting OAuth client (id_oc_*); null off the OAuth path.
                      reason:
                        type: string
                        nullable: true
                        description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                      permissions:
                        type: object
                        additionalProperties: {}
                        description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                      cluster_id:
                        type: integer
                        nullable: true
                        description: "Internal audit context: the cluster that served the write."
                      trace_id:
                        type: string
                        nullable: true
                        description: "Internal audit context: the trace id of the request that wrote the row."
                    required:
                      - actor_type
                      - actor_sid
                      - team_sid
                      - permissions
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  deleted_at:
                    type: string
                    nullable: true
                required:
                  - sid
                  - team_sid
                  - name
                  - description
                  - status
                  - published_version_sid
                  - draft_steps
                  - schedule
                  - on_reply
                  - agent_sid
                  - sender_profile_sids
                  - rotation_strategy
                  - priority
                  - created_by
                  - deleted_by
                  - created_at
                  - updated_at
                  - deleted_at
              included:
                type: object
                properties:
                  published_version:
                    type: object
                    nullable: true
                    properties:
                      sid:
                        type: string
                        description: wf_vr_….
                      workflow_sid:
                        type: string
                        description: wf_wf_… parent.
                      version:
                        type: integer
                        description: Per-workflow sequence, >=1 (max+1 at publish).
                      steps:
                        type: array
                        items:
                          oneOf:
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_connection_request
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                message:
                                  type: string
                                  nullable: true
                                  description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_message
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                message:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                  description: Message template (same namespaces as all templates).
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                              required:
                                - type
                                - message
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_send_inmail
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                subject:
                                  type: string
                                  nullable: true
                                  maxLength: 200
                                message:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                              required:
                                - type
                                - message
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_visit_profile
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_endorse_skills
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                skills_count:
                                  type: integer
                                  minimum: 1
                                  maximum: 10
                                  description: Endorse the person's top N listed skills, 1..10.
                              required:
                                - type
                                - skills_count
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_withdraw_connection_request
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_like_latest_post
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - linkedin_comment_latest_post
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                comment:
                                  type: string
                                  minLength: 1
                                  maxLength: 1250
                                  description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                              required:
                                - type
                                - comment
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - email_send
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                subject:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                                body:
                                  type: string
                                  minLength: 1
                                  maxLength: 100000
                                  description: HTML body template.
                                required_fields:
                                  type: object
                                  nullable: true
                                  properties:
                                    refs:
                                      type: array
                                      items:
                                        type: string
                                        maxLength: 160
                                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                                      maxItems: 20
                                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                                    on_missing:
                                      type: string
                                      enum:
                                        - fail
                                        - skip
                                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                                  required:
                                    - refs
                                    - on_missing
                                  additionalProperties: false
                                email_field:
                                  type: string
                                  nullable: true
                                  description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                                cc:
                                  type: array
                                  nullable: true
                                  items:
                                    type: string
                                    maxLength: 320
                                    format: email
                                  maxItems: 5
                                  description: Up to 5 literal copy addresses.
                                bcc:
                                  type: array
                                  nullable: true
                                  items:
                                    type: string
                                    maxLength: 320
                                    format: email
                                  maxItems: 5
                                  description: Up to 5 literal blind-copy addresses.
                                attachments:
                                  type: array
                                  nullable: true
                                  items:
                                    type: object
                                    properties:
                                      sid:
                                        type: string
                                        minLength: 18
                                        maxLength: 18
                                        pattern: ^wf_at_
                                      name:
                                        type: string
                                        minLength: 1
                                        maxLength: 255
                                    required:
                                      - sid
                                      - name
                                    additionalProperties: false
                                  maxItems: 5
                                  description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                                reply_in_thread:
                                  type: boolean
                                  nullable: true
                                track_opens:
                                  type: boolean
                                  nullable: true
                                track_clicks:
                                  type: boolean
                                  nullable: true
                                unsubscribe_link:
                                  type: boolean
                                  nullable: true
                              required:
                                - type
                                - subject
                                - body
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - wait
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                for:
                                  type: string
                                  pattern: ^[1-9][0-9]*[mhd]$
                                  description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                              required:
                                - type
                                - for
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - wait_for_event
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                event:
                                  type: string
                                  enum:
                                    - linkedin_connection_request_accepted
                                    - email_opened
                                    - email_link_clicked
                                  description: Event observed via the activities ingest.
                                timeout:
                                  type: object
                                  properties:
                                    after:
                                      type: string
                                      pattern: ^[1-9][0-9]*[mhd]$
                                      description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                                    steps:
                                      type: object
                                      additionalProperties: {}
                                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                  required:
                                    - after
                                    - steps
                                  additionalProperties: false
                                  description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                              required:
                                - type
                                - event
                                - timeout
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - condition
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                branches:
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                                      label:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor caption.
                                      when:
                                        type: object
                                        additionalProperties: {}
                                        description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                                      steps:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                    required:
                                      - when
                                      - steps
                                    additionalProperties: false
                                  minItems: 1
                                  maxItems: 9
                                  description: 1..9 branches, evaluated in order, first match wins.
                                else:
                                  type: object
                                  additionalProperties: {}
                                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                              required:
                                - type
                                - branches
                                - else
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - ab_test
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                branches:
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      id:
                                        type: integer
                                        minimum: 1
                                        description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                                      label:
                                        type: string
                                        nullable: true
                                        maxLength: 255
                                        description: Editor caption ("Variant A").
                                      weight:
                                        type: integer
                                        minimum: 1
                                        description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                                      steps:
                                        type: object
                                        additionalProperties: {}
                                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                                    required:
                                      - weight
                                      - steps
                                    additionalProperties: false
                                  minItems: 2
                                  maxItems: 9
                                  description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                              required:
                                - type
                                - branches
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - end
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - api_call
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                method:
                                  type: string
                                  enum:
                                    - GET
                                    - POST
                                    - PUT
                                    - PATCH
                                    - DELETE
                                url:
                                  type: string
                                  minLength: 1
                                  maxLength: 2048
                                  description: https-only (publish check); a template - variables may stand in the path and the query.
                                headers:
                                  type: object
                                  nullable: true
                                  additionalProperties:
                                    type: string
                                    maxLength: 1024
                                query:
                                  type: object
                                  nullable: true
                                  additionalProperties:
                                    type: string
                                    maxLength: 2048
                                body:
                                  type: string
                                  nullable: true
                                  maxLength: 16000
                                  description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                                provider_connection_sid:
                                  type: string
                                  nullable: true
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^in_cn_
                                  description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                                timeout_secs:
                                  type: integer
                                  nullable: true
                                  minimum: 1
                                  maximum: 120
                                retry_on_error:
                                  type: boolean
                                  nullable: true
                                remove_empty_values:
                                  type: boolean
                                  nullable: true
                                output_key:
                                  type: string
                                  nullable: true
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                              required:
                                - type
                                - method
                                - url
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - ask_ai
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                prompt:
                                  type: string
                                  minLength: 1
                                  maxLength: 8000
                                  description: Same variable namespaces as message templates.
                                output_key:
                                  type: string
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                                preset_sid:
                                  type: string
                                  nullable: true
                                  description: gtm-api preset for the AI call; null = team default.
                              required:
                                - type
                                - prompt
                                - output_key
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - manual_task
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                title:
                                  type: string
                                  minLength: 1
                                  maxLength: 255
                                instructions:
                                  type: string
                                  nullable: true
                                  maxLength: 4000
                                  description: Rendered into the human todo; the journey waits until the task is completed.
                              required:
                                - type
                                - title
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - move_to_workflow
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                target_workflow_sid:
                                  type: string
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^wf_wf_
                                  description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                                mode:
                                  type: string
                                  nullable: true
                                  enum:
                                    - from_start
                                    - from_current
                                  description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                              required:
                                - type
                                - target_workflow_sid
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - add_tag
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                tag_sids:
                                  type: array
                                  items:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^cr_tg_
                                  minItems: 1
                                  maxItems: 20
                                  description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                              required:
                                - type
                                - tag_sids
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - remove_tag
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                tag_sids:
                                  type: array
                                  items:
                                    type: string
                                    minLength: 18
                                    maxLength: 18
                                    pattern: ^cr_tg_
                                  minItems: 1
                                  maxItems: 20
                                  description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                              required:
                                - type
                                - tag_sids
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - set_field
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                field_slug:
                                  type: string
                                  pattern: ^[a-z][a-z0-9_]{0,63}$
                                  description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                                value:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                    - {}
                                    - {}
                                  description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                              required:
                                - type
                                - field_slug
                                - value
                              additionalProperties: false
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - change_sender
                                id:
                                  type: integer
                                  minimum: 1
                                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                                name:
                                  type: string
                                  nullable: true
                                  maxLength: 255
                                  description: Editor label.
                                sender_profile_sid:
                                  type: string
                                  nullable: true
                                  minLength: 18
                                  maxLength: 18
                                  pattern: ^ub_sp_
                                  description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                                rotation:
                                  type: string
                                  nullable: true
                                  enum:
                                    - fair
                                    - random
                                    - new_sender
                                    - prior_engagement
                                  description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                              required:
                                - type
                              additionalProperties: false
                        description: Immutable snapshot of the step document at publish.
                      steps_count:
                        type: integer
                        description: Denormalized total step count (incl. nested).
                      entry_step_id:
                        type: integer
                        description: = steps[0].id - enrollment starts here.
                      created_at:
                        type: string
                        description: ISO 8601 UTC - publish moment.
                    required:
                      - sid
                      - workflow_sid
                      - version
                      - steps
                      - steps_count
                      - entry_step_id
                      - created_at
                    description: WorkflowVersionDomain (1:1 via published_version_sid; heavy - full steps JSON) - see ./workflow_versions.md.
                  sources:
                    type: array
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                      required:
                        - sid
                    description: WorkflowSourceDomain audience feeds (1:N, default 50, created_at ASC) - see ./workflow_sources.md.
                  records_counts:
                    type: object
                    properties:
                      total_count:
                        type: integer
                        minimum: 0
                      groups:
                        type: object
                        properties:
                          status:
                            anyOf:
                              - type: object
                                additionalProperties:
                                  type: number
                              - type: array
                                items: {}
                            description: "Journey funnel by WorkflowRecordStatusEnum: waiting_limit / blocked / active / waiting / paused_on_reply / paused_manual / paused_blocked / failed / completed / exited."
                        required:
                          - status
                    required:
                      - total_count
                      - groups
                    description: "WorkflowRecordCounts over { workflow_sid: parent.sid } - the full-scope enrolled/active/replied/done snapshot for the editor header (§4.17a) - see ./workflow_records.md."
                  forecast:
                    type: object
                    nullable: true
                    properties:
                      scheduled_count:
                        type: integer
                        minimum: 0
                        description: Send-class tasks scheduled on a sender profile.
                      sender_profiles_count:
                        type: integer
                        minimum: 0
                      days_to_drain:
                        type: integer
                        nullable: true
                        minimum: 0
                        exclusiveMinimum: true
                        description: Days from today until the last planned send leaves (1 = everything today); null when nothing is planned.
                      drains_on:
                        type: string
                        nullable: true
                        description: YYYY-MM-DD (UTC) of the last send; null past the horizon.
                      over_horizon:
                        type: boolean
                        description: 'The walk stopped at a year: read "over a year".'
                      buckets:
                        type: array
                        items:
                          type: object
                          properties:
                            sender_profile_sid:
                              type: string
                            type:
                              type: string
                              description: The send-class task type.
                            scheduled_count:
                              type: integer
                              minimum: 0
                            daily_share:
                              type: integer
                              minimum: 0
                              description: This workflow's share of the (sender profile, type) daily cap, by priority (the sender profile pick's split).
                            days_to_drain:
                              type: integer
                              minimum: 0
                            over_horizon:
                              type: boolean
                          required:
                            - sender_profile_sid
                            - type
                            - scheduled_count
                            - daily_share
                            - days_to_drain
                            - over_horizon
                      timeline:
                        type: array
                        items:
                          type: object
                          properties:
                            day:
                              type: string
                              description: YYYY-MM-DD, UTC.
                            planned:
                              type: integer
                              minimum: 0
                            by_type:
                              type: object
                              additionalProperties:
                                type: integer
                                minimum: 0
                          required:
                            - day
                            - planned
                            - by_type
                        description: The first 60 days; every bucket added up per day.
                    required:
                      - scheduled_count
                      - sender_profiles_count
                      - days_to_drain
                      - drains_on
                      - over_horizon
                      - buckets
                      - timeline
                    description: "How long the planned sends take at the current limits (TASK_EXECUTION_ARCHITECTURE.md §6.5, D41): the scheduled tasks per (sender profile, type) laid over the days ahead at the workflow's priority share of the sender profile's daily cap, closed days skipped. Computed on read from counts, never stored; rows held at the door are not in it."
            required:
              - item
              - included
        pagination:
          type: object
          properties:
            next_cursor:
              type: string
              nullable: true
            has_more:
              type: boolean
            total_count:
              type: integer
              nullable: true
          required:
            - next_cursor
            - has_more
            - total_count
        applied_filters:
          type: object
          additionalProperties: {}
        includes:
          type: array
          items:
            type: string
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
        counts:
          type: object
          properties:
            total_count:
              type: integer
              minimum: 0
              description: Workflow rows matching the filter scope.
            groups:
              type: object
              properties:
                status:
                  anyOf:
                    - type: object
                      properties:
                        draft:
                          type: integer
                          minimum: 0
                        active:
                          type: integer
                          minimum: 0
                        paused:
                          type: integer
                          minimum: 0
                        archived:
                          type: integer
                          minimum: 0
                    - type: array
                      items: {}
                  description: Campaign distribution by status (feeds list badges); absent key = zero (PHP empty map serialises as []).
              required:
                - status
          required:
            - total_count
            - groups
      required:
        - success
        - operation
        - items
        - pagination
        - applied_filters
        - includes
        - meta
    SuggestCompanyFilterValuesRequest:
      type: object
      description: Request body of `suggest_company_filter_values`.
      properties:
        field:
          type: string
          enum:
            - tag_sids
          description: Facetable field. tag_sids returns tag sids - resolve labels via tags search.
        term:
          type: string
          maxLength: 64
          description: Prefix/infix narrowing; omit for top values.
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
              additionalProperties: false
              description: Prefix-validated cr_co_ sid(s).
            playtable_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every company tab passes { in: [<table>] }; array-overlap. nin answers the complement, memberless rows included."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The account's funnel bucket (one of seven), expanded on the server into the team's company stage sids of those categories: ask by name, never resolve the stages yourself. eq approaching = someone was invited or written to and nobody answered."
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the account, all must hold: its own visit and the account names rolled up over the people to work (disqualified or stoplisted people do not count). Never compose the roll-ups yourself. A person's or a thread's name is a 422."
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance (ds_sc_…).
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                  description: Company sid (cr_co_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                    description: Company sid (cr_co_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap (any of); cr_tg_ sids - resolve labels via tags. nin answers the complement, untagged rows included.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact LinkedIn company id.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact page slug; fuzzy matching goes through q.
            domain:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Lowercased apex; is_null = enrichment gap.
            name:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact match; substring goes through q.
            q:
              type: string
              maxLength: 128
              description: Free text over name, domain, website, ln_nickname (ES full-text).
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scope (typically { playtable_sids: { in: […] } })."
        limit:
          type: integer
          minimum: 1
          maximum: 50
          description: Default 20.
      required:
        - field
    SuggestCompanyFilterValuesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            suggestions:
              type: array
              items:
                type: object
                properties:
                  value:
                    type: string
                    description: Distinct field value (cr_tg_ sid for tag_sids).
                  count:
                    type: integer
                    minimum: 0
                    description: Matching rows within the filter scope.
                required:
                  - value
                  - count
          required:
            - suggestions
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    SuggestDataSourceFilterValuesRequest:
      type: object
      description: Request body of `suggest_data_source_filter_values`.
      properties:
        key:
          type: string
          minLength: 1
          maxLength: 64
          description: "Semantic key: locations | industries | current_companies | past_companies | schools | seniorities | functions | company_sizes | company_types. Wire key: the first five as {id}; seniorities = seniority_levels, company_sizes = company_headcounts, flat ids."
        query:
          type: string
          minLength: 1
          maxLength: 100
          description: 'The term as the user said it ("Berlin", "fintech", "Stripe"); the fixed-list facets ignore it and answer their whole list. A busy pool answers 503 or 429 with context.retry_after: wait, then call again.'
      required:
        - key
        - query
    SuggestDataSourceFilterValuesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            rows:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                    description: "The opaque facet id: put it VERBATIM into the filter set ({id} or a flat id, per the key)."
                  display_name:
                    type: string
                    nullable: true
                    description: The option's label ("Berlin, Germany", "Financial Services", "CXO").
                required:
                  - id
              description: "Matching options in the search's order, [] on no match. The fixed-list facets (seniorities, functions, company_sizes, company_types) answer their whole list whatever the query: pick by label."
          required:
            - rows
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    SuggestPersonFilterValuesRequest:
      type: object
      description: Request body of `suggest_person_filter_values`.
      properties:
        field:
          type: string
          enum:
            - company_name
            - tag_sids
          description: "Facet field: company_name (the resolved company name) | tag_sids (returns tag sids)."
        term:
          type: string
          maxLength: 64
          description: Prefix/infix narrowing; omit for top values.
        filter:
          type: object
          properties:
            sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
              additionalProperties: false
              description: Prefix-validated cr_pp_ sid(s).
            playtable_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^pt_tb_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^pt_tb_
              additionalProperties: false
              description: "THE table context - every table view passes { eq: <table> }."
            pipeline_stage_category:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - cold
                    - approaching
                    - engaging
                    - positive
                    - nurture
                    - negative
                    - disqualified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - cold
                      - approaching
                      - engaging
                      - positive
                      - nurture
                      - negative
                      - disqualified
              additionalProperties: false
              description: "The stage's funnel bucket (one of seven), expanded on the server into the team's person stage sids of those categories: ask by name, never resolve stages. eq approaching = we reached out, nothing came back; in [engaging, positive] = something came back."
            company_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_co_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_co_
                is_null:
                  type: boolean
              additionalProperties: false
            data_source_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^ds_sc_
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^ds_sc_
                is_null:
                  type: boolean
              additionalProperties: false
              description: Import provenance.
            status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                ne:
                  type: string
                  enum:
                    - ok
                    - failed_validation
                    - no_contact_data
                    - duplicate
                    - stoplisted
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - ok
                      - failed_validation
                      - no_contact_data
                      - duplicate
                      - stoplisted
              additionalProperties: false
            duplicate_of_sid:
              type: object
              properties:
                eq:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^cr_pp_
                  description: Person sid (cr_pp_…).
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_pp_
                    description: Person sid (cr_pp_…).
                is_null:
                  type: boolean
              additionalProperties: false
              description: "The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates."
            linkedin_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                ne:
                  type: string
                  enum:
                    - need_enrichment
                    - enrichment_failed
                    - no_data
                    - blocked
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_enrichment
                      - enrichment_failed
                      - no_data
                      - blocked
                      - ok
              additionalProperties: false
            email_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - bounced
                    - ok
                    - catch_all
                    - unverified
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - bounced
                      - ok
                      - catch_all
                      - unverified
                is_null:
                  type: boolean
              additionalProperties: false
            phone_status:
              type: object
              properties:
                eq:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                ne:
                  type: string
                  enum:
                    - need_search
                    - no_data
                    - ok
                in:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                nin:
                  type: array
                  items:
                    type: string
                    enum:
                      - need_search
                      - no_data
                      - ok
                is_null:
                  type: boolean
              additionalProperties: false
            tag_sids:
              type: object
              properties:
                in:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                nin:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
              additionalProperties: false
              description: Array-overlap semantics (any of) - in matches rows whose tag array overlaps the list; nin answers the complement, untagged rows included.
            signals:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    enum:
                      - awaiting_reply
                      - opened_not_replied
                      - clicked_not_replied
                      - multi_opened
                      - accepted_not_replied
                      - note_read_not_replied
                      - reacted_not_replied
                      - invited_us
                      - followed_us
                      - lead_messaged_first
                      - unanswered_inbound
                      - draft_pending
                      - escalated_open
                      - task_overdue
                      - went_quiet
                      - reactivated
                      - invite_pending
                      - connection_removed
                      - blocked_us
                      - deleted_message
                      - bounced
                      - bounced_hard
                      - complained
                      - booking_link_sent
                      - objective_reached
                      - viewed_our_profile
                      - visited_our_site
                      - visited_not_replied
                      - visited_key_page
                      - multi_visited
                      - submitted_form
                      - company_visited_our_site
                      - no_people
                      - thin_coverage
                      - nobody_reached
                      - no_engagement
                      - no_reply
                      - exhausted
                      - dormant
                      - dm_missing
                    description: "A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted)."
                  age_days:
                    type: integer
                    minimum: 0
                    maximum: 3650
                    description: "At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age."
                required:
                  - key
              minItems: 1
              maxItems: 9
              description: "ES-only. Named signals of the person, all must hold. The server expands a name into its keyword and clock range: never compose them. A bare entry takes the catalog default age, age_days moves it. A thread-only name is a 422 (ask search_conversations)."
            ln_member_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact identifier.
            ln_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw profile URN.
            sn_id:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact raw Sales Navigator URN.
            ln_nickname:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: Exact vanity slug (lowercased); use q for fuzzy.
            work_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: is_null:true = coverage gap.
            personal_email:
              type: object
              properties:
                eq:
                  type: string
                in:
                  type: array
                  items:
                    type: string
                is_null:
                  type: boolean
              additionalProperties: false
            q:
              type: string
              maxLength: 128
              description: Free text (ES people index) over the resolved name and company name, the emails and the slug. Filter a company by company_sid.
            created_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
              description: ISO 8601 range; combine bounds in one object.
            updated_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                gt:
                  type: string
                lt:
                  type: string
              additionalProperties: false
            deleted_at:
              type: object
              properties:
                gte:
                  type: string
                lte:
                  type: string
                is_null:
                  type: boolean
              additionalProperties: false
              description: "Default scope is { is_null: true } (live rows)."
          description: "Scope - typically { playtable_sid: { eq: … } }."
        limit:
          type: integer
          minimum: 1
          maximum: 50
          description: 1..50, default 20.
      required:
        - field
    SuggestPersonFilterValuesResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            suggestions:
              type: array
              items:
                type: object
                properties:
                  value:
                    type: string
                    description: Distinct field value (a tag sid when field=tag_sids).
                  count:
                    type: integer
                    minimum: 0
                    description: Matching rows within the filter scope.
                required:
                  - value
                  - count
          required:
            - suggestions
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    TestApiCallWorkflowRequest:
      type: object
      description: Request body of `test_api_call_workflow`.
      properties:
        step:
          oneOf:
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_send_connection_request
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                message:
                  type: string
                  nullable: true
                  description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                required_fields:
                  type: object
                  nullable: true
                  properties:
                    refs:
                      type: array
                      items:
                        type: string
                        maxLength: 160
                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                      maxItems: 20
                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                    on_missing:
                      type: string
                      enum:
                        - fail
                        - skip
                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                  required:
                    - refs
                    - on_missing
                  additionalProperties: false
              required:
                - type
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_send_message
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                message:
                  type: string
                  minLength: 1
                  maxLength: 8000
                  description: Message template (same namespaces as all templates).
                required_fields:
                  type: object
                  nullable: true
                  properties:
                    refs:
                      type: array
                      items:
                        type: string
                        maxLength: 160
                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                      maxItems: 20
                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                    on_missing:
                      type: string
                      enum:
                        - fail
                        - skip
                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                  required:
                    - refs
                    - on_missing
                  additionalProperties: false
              required:
                - type
                - message
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_send_inmail
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                subject:
                  type: string
                  nullable: true
                  maxLength: 200
                message:
                  type: string
                  minLength: 1
                  maxLength: 8000
                required_fields:
                  type: object
                  nullable: true
                  properties:
                    refs:
                      type: array
                      items:
                        type: string
                        maxLength: 160
                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                      maxItems: 20
                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                    on_missing:
                      type: string
                      enum:
                        - fail
                        - skip
                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                  required:
                    - refs
                    - on_missing
                  additionalProperties: false
              required:
                - type
                - message
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_visit_profile
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
              required:
                - type
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_endorse_skills
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                skills_count:
                  type: integer
                  minimum: 1
                  maximum: 10
                  description: Endorse the person's top N listed skills, 1..10.
              required:
                - type
                - skills_count
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_withdraw_connection_request
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
              required:
                - type
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_like_latest_post
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
              required:
                - type
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - linkedin_comment_latest_post
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                comment:
                  type: string
                  minLength: 1
                  maxLength: 1250
                  description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                required_fields:
                  type: object
                  nullable: true
                  properties:
                    refs:
                      type: array
                      items:
                        type: string
                        maxLength: 160
                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                      maxItems: 20
                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                    on_missing:
                      type: string
                      enum:
                        - fail
                        - skip
                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                  required:
                    - refs
                    - on_missing
                  additionalProperties: false
              required:
                - type
                - comment
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - email_send
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                subject:
                  type: string
                  minLength: 1
                  maxLength: 255
                body:
                  type: string
                  minLength: 1
                  maxLength: 100000
                  description: HTML body template.
                required_fields:
                  type: object
                  nullable: true
                  properties:
                    refs:
                      type: array
                      items:
                        type: string
                        maxLength: 160
                        pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                      maxItems: 20
                      description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                    on_missing:
                      type: string
                      enum:
                        - fail
                        - skip
                      description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                  required:
                    - refs
                    - on_missing
                  additionalProperties: false
                email_field:
                  type: string
                  nullable: true
                  description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                cc:
                  type: array
                  nullable: true
                  items:
                    type: string
                    maxLength: 320
                    format: email
                  maxItems: 5
                  description: Up to 5 literal copy addresses.
                bcc:
                  type: array
                  nullable: true
                  items:
                    type: string
                    maxLength: 320
                    format: email
                  maxItems: 5
                  description: Up to 5 literal blind-copy addresses.
                attachments:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_at_
                      name:
                        type: string
                        minLength: 1
                        maxLength: 255
                    required:
                      - sid
                      - name
                    additionalProperties: false
                  maxItems: 5
                  description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                reply_in_thread:
                  type: boolean
                  nullable: true
                track_opens:
                  type: boolean
                  nullable: true
                track_clicks:
                  type: boolean
                  nullable: true
                unsubscribe_link:
                  type: boolean
                  nullable: true
              required:
                - type
                - subject
                - body
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - wait
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                for:
                  type: string
                  pattern: ^[1-9][0-9]*[mhd]$
                  description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
              required:
                - type
                - for
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - wait_for_event
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                event:
                  type: string
                  enum:
                    - linkedin_connection_request_accepted
                    - email_opened
                    - email_link_clicked
                  description: Event observed via the activities ingest.
                timeout:
                  type: object
                  properties:
                    after:
                      type: string
                      pattern: ^[1-9][0-9]*[mhd]$
                      description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    steps:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - after
                    - steps
                  additionalProperties: false
                  description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
              required:
                - type
                - event
                - timeout
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - condition
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                branches:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                      label:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor caption.
                      when:
                        type: object
                        additionalProperties: {}
                        description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                      steps:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - when
                      - steps
                    additionalProperties: false
                  minItems: 1
                  maxItems: 9
                  description: 1..9 branches, evaluated in order, first match wins.
                else:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - type
                - branches
                - else
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - ab_test
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                branches:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                      label:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor caption ("Variant A").
                      weight:
                        type: integer
                        minimum: 1
                        description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                      steps:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - weight
                      - steps
                    additionalProperties: false
                  minItems: 2
                  maxItems: 9
                  description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
              required:
                - type
                - branches
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - end
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
              required:
                - type
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - api_call
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                method:
                  type: string
                  enum:
                    - GET
                    - POST
                    - PUT
                    - PATCH
                    - DELETE
                url:
                  type: string
                  minLength: 1
                  maxLength: 2048
                  description: https-only (publish check); a template - variables may stand in the path and the query.
                headers:
                  type: object
                  nullable: true
                  additionalProperties:
                    type: string
                    maxLength: 1024
                query:
                  type: object
                  nullable: true
                  additionalProperties:
                    type: string
                    maxLength: 2048
                body:
                  type: string
                  nullable: true
                  maxLength: 16000
                  description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                provider_connection_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^in_cn_
                  description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                timeout_secs:
                  type: integer
                  nullable: true
                  minimum: 1
                  maximum: 120
                retry_on_error:
                  type: boolean
                  nullable: true
                remove_empty_values:
                  type: boolean
                  nullable: true
                output_key:
                  type: string
                  nullable: true
                  pattern: ^[a-z][a-z0-9_]{0,63}$
                  description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
              required:
                - type
                - method
                - url
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - ask_ai
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                prompt:
                  type: string
                  minLength: 1
                  maxLength: 8000
                  description: Same variable namespaces as message templates.
                output_key:
                  type: string
                  pattern: ^[a-z][a-z0-9_]{0,63}$
                  description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset for the AI call; null = team default.
              required:
                - type
                - prompt
                - output_key
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - manual_task
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                title:
                  type: string
                  minLength: 1
                  maxLength: 255
                instructions:
                  type: string
                  nullable: true
                  maxLength: 4000
                  description: Rendered into the human todo; the journey waits until the task is completed.
              required:
                - type
                - title
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - move_to_workflow
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                target_workflow_sid:
                  type: string
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                mode:
                  type: string
                  nullable: true
                  enum:
                    - from_start
                    - from_current
                  description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
              required:
                - type
                - target_workflow_sid
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - add_tag
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                tag_sids:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                  minItems: 1
                  maxItems: 20
                  description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
              required:
                - type
                - tag_sids
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - remove_tag
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                tag_sids:
                  type: array
                  items:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^cr_tg_
                  minItems: 1
                  maxItems: 20
                  description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
              required:
                - type
                - tag_sids
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - set_field
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                field_slug:
                  type: string
                  pattern: ^[a-z][a-z0-9_]{0,63}$
                  description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                value:
                  anyOf:
                    - type: string
                    - type: number
                    - type: boolean
                    - {}
                    - {}
                  description: Scalar cell value (one cell; no arrays/objects); null clears the field.
              required:
                - type
                - field_slug
                - value
              additionalProperties: false
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - change_sender
                id:
                  type: integer
                  minimum: 1
                  description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                name:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Editor label.
                sender_profile_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                  description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                rotation:
                  type: string
                  nullable: true
                  enum:
                    - fair
                    - random
                    - new_sender
                    - prior_engagement
                  description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
              required:
                - type
              additionalProperties: false
        people_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^cr_pp_
          description: A person of the team; the templates render against their row.
      required:
        - step
        - people_sid
    TestApiCallWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          enum:
            - test-api-call
        item: {}
        result:
          type: object
          properties:
            request:
              type: object
              properties:
                method:
                  type: string
                url:
                  type: string
                headers:
                  type: object
                  additionalProperties:
                    type: string
                body: {}
                provider_connection_sid:
                  type: string
                  nullable: true
                timeout_secs:
                  type: integer
              required:
                - method
                - url
                - headers
                - provider_connection_sid
                - timeout_secs
            status:
              type: string
              enum:
                - success
                - failed
            http_status:
              type: integer
              nullable: true
            response: {}
            error_code:
              type: string
              nullable: true
            error_message:
              type: string
              nullable: true
            provider_call_sid:
              type: string
              nullable: true
          required:
            - request
            - status
            - http_status
            - error_code
            - error_message
            - provider_call_sid
        meta:
          type: object
          additionalProperties: {}
      required:
        - success
        - operation
        - action
        - item
        - result
    UpdateCompanyRequest:
      type: object
      description: Request body of `update_company`.
      properties:
        name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 511
          description: A manual observation that outranks every source until reset; the linked people show it (their items, documents and templates resolve it).
        logo_url:
          type: string
          nullable: true
          maxLength: 2048
          format: uri
          description: New logo URL (max 2048), a manual observation; null records a manual none (the domain favicon).
        ln_id:
          type: string
          nullable: true
          maxLength: 255
          description: Identity edit - a collision with another live account flags this row status=duplicate (never a 409); the linked people's documents follow.
        ln_nickname:
          type: string
          nullable: true
          maxLength: 255
          description: Identity edit - dedup guard re-runs; a page URL is reduced to the slug in place.
        website:
          type: string
          nullable: true
          maxLength: 511
          format: uri
          description: The full URL, a manual observation; domain is not derived on update.
        domain:
          type: string
          nullable: true
          maxLength: 255
          description: Identity edit - dedup guard re-runs; normalized in place.
        deal_size:
          type: number
          nullable: true
          description: Deal value (decimal 15,2); null clears it.
        tag_sids:
          type: array
          nullable: true
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Full-replace (not a merge).
        external_refs:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Free-form CRM sync hook, full-replace; round-tripped as-is.
    UpdateCompanyResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sids:
              type: array
              items:
                type: string
              description: Member tables (pt_tb_…) - MULTI membership; service-managed (create/import union, detach / table-delete pull); may be empty. Filtering/counting on it is ES-served.
            data_source_sid:
              type: string
              nullable: true
            data_source_type:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
              description: Numeric LinkedIn company id - strongest dedup key.
            ln_nickname:
              type: string
              nullable: true
              description: "The company page vanity slug (acme-corp), lowercased; a page URL is reduced to it on write, never stored (SERVICE_CONVENTIONS §Y). Dedup key #2."
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                picture_url:
                  type: string
                  nullable: true
                  description: "The logo: a permanent copy over a wire link; null = the reader falls back to the domain favicon."
                website:
                  type: string
                  nullable: true
                  description: The full URL a source gave; domain on the row stays the identifier.
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - picture_url
                - website
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, the logo and the website a surface or a model shows next to the row, resolved at read from the observations ledger with the same precedence as a person's. The only place these words are: the row keeps identifiers (phase E, 2026-10-22)."
            domain:
              type: string
              nullable: true
              description: "Lowercased apex domain; derived from website when absent; dedup key #3."
            deal_size:
              type: number
              nullable: true
              description: Deal value attached to the account (decimal 15,2) - the one client-writable business column.
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - duplicate
                - stoplisted
              description: Service-managed (import validation, stoplist); not client-writable.
            status_reason:
              type: string
              nullable: true
              description: "Human-readable context for the current status (validation error, matched stoplist identifier); service-written together with status. A duplicate carries none: its pointer is duplicate_of_sid."
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY account (cr_co_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_company_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_id
                - ln_nickname
                - domain
              description: "While status is duplicate: the identity column the late write collided on. Null otherwise."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: 'Free-form CRM sync hook ({ hubspot_company_id: "902", … }); keys are integration-defined, stored as-is, round-tripped, never validated; PHP empty map serialises as [].'
            last_enrich_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; stamped when an enrichment cycle completes - drives enrichment scheduling.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: "The funnel stage the company is in (cr_ps_...): derived from its people unless pinned (pipeline_stages.md); null = no stage."
            pipeline_stage_source:
              type: string
              nullable: true
              enum:
                - derived
                - manual
              description: "How the stage was set (CompanyPipelineStageSourceEnum): derived from the people, or pinned by a manual move; reset_pipeline_stages_derivation drops the pin. Null with no stage."
          required:
            - sid
            - team_sid
            - playtable_sids
            - data_source_sid
            - data_source_type
            - data_source_item_sid
            - ln_id
            - ln_nickname
            - context
            - domain
            - deal_size
            - status
            - status_reason
            - duplicate_of_sid
            - duplicate_matched_kind
            - tag_sids
            - external_refs
            - last_enrich_at
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
            - pipeline_stage_source
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateDataSourceRequest:
      type: object
      description: Request body of `update_data_source`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New display name (1..255).
        status:
          type: string
          enum:
            - active
            - paused
          description: "User transitions only: pause / resume, and failed to active (re-arms the collect clock after a config fix). Anything else is 422 invalid_transition; completed is system-set."
        field_mapping:
          type: array
          nullable: true
          items:
            type: object
            properties:
              source:
                type: string
                minLength: 1
                maxLength: 512
                description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
              target_kind:
                type: string
                enum:
                  - people_attribute
                  - company_attribute
                  - field_slug
                description: people_attribute | company_attribute | field_slug.
              target:
                type: string
                minLength: 1
                maxLength: 255
                description: Attribute key (people / company) or a playtable field slug in the target table.
              name:
                type: string
                nullable: true
                minLength: 1
                maxLength: 255
                description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
            required:
              - source
              - target_kind
              - target
          description: Full-replace of the mapping; affects pending + retried rows only, never already-promoted ones.
        payload:
          type: object
          properties:
            prompt:
              type: string
              maxLength: 2000
              description: "ai_search, find_people. Accepted only while the source holds no plan (it waits for one, or its plan failed): once the filter is built from a description, a different description is a new source (422 on payload.prompt, rule `plan_built`)."
            per_company_limit:
              type: integer
              minimum: 1
              maximum: 25
              description: find_people only (1..25).
            repeat:
              type: string
              nullable: true
              enum:
                - hourly
                - daily
                - weekly
                - monthly
              description: sender_search, post_engagement. hourly | daily | weekly | monthly, or null to stop repeating.
            window:
              anyOf:
                - type: object
                  properties:
                    days:
                      anyOf:
                        - type: number
                          enum:
                            - 7
                        - type: number
                          enum:
                            - 30
                        - type: number
                          enum:
                            - 90
                  required:
                    - days
                  additionalProperties: false
                - type: object
                  properties:
                    since:
                      type: string
                      pattern: ^\d{4}-\d{2}-\d{2}$
                  required:
                    - since
                  additionalProperties: false
              description: "post_engagement, a person or a company: the next run reads the posts of the new window."
            relevance:
              type: object
              nullable: true
              properties:
                prompt:
                  type: string
                  minLength: 1
                  maxLength: 2000
              required:
                - prompt
              additionalProperties: false
              description: "post_engagement: the AI post filter for the posts not judged yet; null switches it off, so every post is walked."
            collect:
              type: object
              properties:
                reactions:
                  type: boolean
                comments:
                  type: boolean
                reposts:
                  type: boolean
              additionalProperties: false
              description: "post_engagement: the feeds the next run collects; all three off is 422 rule required."
            url:
              type: string
              description: "sender_search only. A replacement link that must classify to the SAME platform, surface and object as the saved one (422 on payload.url, rule `agreement`, otherwise: save a different link as a new source). An unrecognized link is 422 link_not_recognized."
            records_path:
              type: string
              description: webhook only.
          description: "Merged into the stored payload, only the keys the kind lets a caller change: ai_search {prompt}, sender_search {repeat, url}, post_engagement {repeat, window, relevance, collect}, find_people {per_company_limit, prompt}, webhook {records_path}; else 422."
        tag_sids:
          type: array
          nullable: true
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Full-replace of the tag array; applies to future promotions.
        on_duplicate:
          type: string
          enum:
            - skip
            - move
          description: New duplicate-person policy for the rows promoted from now on.
        add_tags_to_duplicate:
          type: boolean
          description: Merge tag_sids onto matched duplicates from now on.
        qualify:
          type: object
          nullable: true
          properties:
            "on":
              type: boolean
              description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
            criterion:
              type: string
              nullable: true
              minLength: 1
              maxLength: 2000
              description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
          required:
            - "on"
            - criterion
          additionalProperties: false
          description: The whole {on, criterion} block, or null to switch the check off; applies to rows not yet promoted.
        sender_profile_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: "Reassign the sender profile of a sender_search or a post_engagement (ub_sp_): the checks run again (linkedin_account_missing, sales_nav_required, recruiter_required, recruiter_signed_out). Those two kinds must keep one; any other kind keeps it null."
    UpdateDataSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              nullable: true
              description: pt_tb_… target table, required on every create; becomes null only when the target playtable is deleted (the source auto-pauses, status_reason=playtable_deleted).
            name:
              type: string
              description: 'min 1, max 255. Defaulted from the kind and its link when omitted on create ("Sales Navigator saved search", "My conversations", "AI search: CMOs in DACH").'
            type:
              type: string
              enum:
                - ai_search
                - sender_search
                - post_engagement
                - find_people
                - csv
                - webhook
              description: "[ro] The source kind: ai_search | sender_search | post_engagement | find_people | csv | webhook. Immutable after create."
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What promoted items become: people | company. An input of create, not a derivation of type; [ro] once the source is past draft (a csv draft's import step may still change it)."
            sender_profile_sid:
              type: string
              nullable: true
              description: ub_sp_… the sender profile whose own LinkedIn account collects. Required for type=sender_search and post_engagement, null for every other kind - see ./sender_profiles.md.
            ingest_key:
              type: string
              nullable: true
              description: "type=webhook only: the 40-char capability secret in the ingest URL ({api_base}/external/ingest/{ingest_key}). Stored plaintext by design so the URL stays re-viewable; rotate-ingest-key revokes it. null for every other kind."
            payload:
              anyOf:
                - type: object
                  properties:
                    platform:
                      type: string
                      enum:
                        - linkedin
                        - sales_navigator
                        - recruiter
                      description: "ai_search (link mode) and sender_search: which LinkedIn product the link opens in."
                    surface:
                      type: string
                      enum:
                        - search
                        - saved_search
                        - list
                        - post
                        - my_network
                        - messenger
                      description: "ai_search (link mode) and sender_search: what kind of list the link is."
                    repeat:
                      type: string
                      nullable: true
                      enum:
                        - hourly
                        - daily
                        - weekly
                        - monthly
                      description: "sender_search, post_engagement: the rerun interval; absent or null = runs once."
                    mode:
                      type: string
                      enum:
                        - create
                        - update
                      description: "csv: what the import does with its rows."
                    target:
                      type: string
                      enum:
                        - post
                        - person
                        - company
                      description: "post_engagement: what the source watches; the axis beside it names it (post.urn, person.ln_nickname, or company.ln_nickname with ln_id, name and logo_url once the walk resolved the page). A link is never stored: rebuild it from the axis."
                    window:
                      anyOf:
                        - type: object
                          properties:
                            days:
                              anyOf:
                                - type: number
                                  enum:
                                    - 7
                                - type: number
                                  enum:
                                    - 30
                                - type: number
                                  enum:
                                    - 90
                          required:
                            - days
                          additionalProperties: false
                        - type: object
                          properties:
                            since:
                              type: string
                              pattern: ^\d{4}-\d{2}-\d{2}$
                          required:
                            - since
                          additionalProperties: false
                      description: "post_engagement, a person or a company: the window the posts are read from."
                    relevance:
                      type: object
                      properties:
                        prompt:
                          type: string
                      required:
                        - prompt
                      description: "post_engagement: the AI post filter; absent = every post is walked."
                    collect:
                      type: object
                      properties:
                        reactions:
                          type: boolean
                        comments:
                          type: boolean
                        reposts:
                          type: boolean
                      additionalProperties: false
                      description: "post_engagement: the feeds the walk collects."
                    posts:
                      type: array
                      items:
                        type: object
                        properties:
                          urn:
                            type: string
                          title:
                            type: string
                          published_at:
                            type: string
                            nullable: true
                          verdict:
                            type: string
                            enum:
                              - match
                              - skip
                          verdict_reason:
                            type: string
                        required:
                          - urn
                      description: "post_engagement: the posts the walk read, newest first, each with its title (the first line), text, author, published_at, counts, the filter's verdict with the reason of a skip, and the walk's cursor per feed (feeds.reactors | comments | resharers: {cursor} or {done: true})."
                - type: array
                  items: {}
              description: "Kind-discriminated config JSON, validated per kind server-side. ai_search: prompt | url + platform + surface, filters + engine (the stored plan), plan_chips / plan_warnings, next_page / latest_page (the walk cursor), collect_error (what stopped the walk: kind transient | refused, http, code, reason, message, fields; with status_reason collect_failed | collect_interrupted). sender_search: url + platform + surface, repeat, and the collector's own cursor (next_page / latest_page for the Recruiter walker, poll_since / poll_cursor / poll_max for the network and inbox pollers; the bus-served surfaces keep none). find_people: company_sids, next_index, per_company_limit, prompt, filters + engine. csv: file_path, file_type, mode, total_rows, config, match. webhook: records_path. post_engagement (2026-10-28): target + post {urn} | person {ln_nickname; ln_id, ln_member_id, name once resolved} | company {ln_nickname, ln_id, name, logo_url}, window, relevance, collect, repeat, and the walk's own state: stage (posts | judge | engage | done), posts (what it read, with verdicts and feed cursors), cycle, next_page / latest_page, migrated_from on a row born as a search with a post link before the kind existed."
            field_mapping:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  source:
                    type: string
                    minLength: 1
                    maxLength: 512
                    description: CSV column index as a string ("3") or JSON path into the webhook body ("contact.email").
                  target_kind:
                    type: string
                    enum:
                      - people_attribute
                      - company_attribute
                      - field_slug
                    description: people_attribute | company_attribute | field_slug.
                  target:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: Attribute key (people / company) or a playtable field slug in the target table.
                  name:
                    type: string
                    nullable: true
                    minLength: 1
                    maxLength: 255
                    description: Display name for the column a field_slug target creates (the header renamed in the mapping UI); null = the CSV header names it. Ignored for the attribute kinds and for fields that already exist.
                required:
                  - source
                  - target_kind
                  - target
              description: "source→target entries: set at import for csv (and may be []), an optional override for webhook (absent = attribute auto-detect at promotion), forbidden for the three search kinds (their collector emits the canonical parser shape)."
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
              description: cr_tg_… each - tags applied to every promoted object - see ./tags.md.
            qualify:
              type: object
              nullable: true
              properties:
                "on":
                  type: boolean
                  description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                criterion:
                  type: string
                  nullable: true
                  minLength: 1
                  maxLength: 2000
                  description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
              required:
                - "on"
                - criterion
              additionalProperties: false
              description: 'The source gate, "Check on save": null = no check. The promotion reads it before a row is born (see ./data_source_items.md Lifecycle 6.5).'
            on_duplicate:
              type: string
              enum:
                - skip
                - move
              description: Duplicate-person policy; default 'skip'.
            add_tags_to_duplicate:
              type: boolean
              description: Merge tag_sids onto matched duplicates; default false.
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - completed
                - failed
            status_reason:
              type: string
              nullable: true
              description: "Reason token behind a paused or failed state (max 2048): playtable_deleted, sales_nav_required, recruiter_required, recruiter_reauth_required, executor_account_missing, plan_failed, collect_failed, collect_interrupted, post_unavailable (the post could not be read: deleted or private), target_not_found (no page at the slug), allowance_exhausted (the AI post filter ran out of credits; paused), …"
            next_collect_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - the collect clock of a search kind, advanced by checkpoints and the repeat interval. null for csv and webhook, and nulled on a bus-served sender search once its scrapes are provisioned (gtm-api owns the cadence from then on).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - name
            - type
            - object_type
            - sender_profile_sid
            - ingest_key
            - payload
            - field_mapping
            - tag_sids
            - qualify
            - on_duplicate
            - add_tags_to_duplicate
            - status
            - status_reason
            - next_collect_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateNoteRequest:
      type: object
      description: Request body of `update_note`.
      properties:
        body:
          type: string
          maxLength: 65535
          description: Replacement text (full replace, plain text). 1..65535 chars on a person or company note; a sticker may be emptied ("").
        step_id:
          type: integer
          nullable: true
          minimum: 1
          description: "A sticker only: move it beside another step of its workflow (null = the workflow as a whole)."
        position:
          type: object
          nullable: true
          properties:
            x:
              type: integer
              minimum: -50000
              maximum: 50000
            "y":
              type: integer
              minimum: -50000
              maximum: 50000
          required:
            - x
            - "y"
          additionalProperties: false
          description: "A sticker only: where a person dragged it; null hands its place back to the canvas. A model leaves it out."
    UpdateNoteResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Note sid (cr_nt_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            object_type:
              type: string
              enum:
                - person
                - company
                - workflow
              description: "Kind of the annotated object: person | company | workflow (a sticker on its canvas). Fixed at create - a note is never re-homed."
            object_sid:
              type: string
              description: The annotated person (cr_pp_…), company (cr_co_…) or workflow (wf_wf_…); prefix matches object_type.
            body:
              type: string
              description: Plain-text note body, rendered as-is; FULLTEXT-indexed for filter.q. 1..65535 chars on a person or company; a sticker may be empty.
            step_id:
              type: integer
              nullable: true
              description: "A sticker only: the workflow step it sits beside; null = the workflow as a whole (and always null on a person or company note)."
            position:
              type: object
              nullable: true
              properties:
                x:
                  type: integer
                  minimum: -50000
                  maximum: 50000
                "y":
                  type: integer
                  minimum: -50000
                  maximum: 50000
              required:
                - x
                - "y"
              additionalProperties: false
              description: "A sticker only: where a person dragged it, relative to its step; null = the canvas places it beside its step."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that authored the note (AccessIdentityValue); shown for accountability.
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the note (tool call or parent cascade); null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC; bumped by body edits.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - object_type
            - object_sid
            - body
            - step_id
            - position
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePersonRequest:
      type: object
      description: Request body of `update_person`.
      properties:
        full_name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: "New display name (1..255): a manual observation that outranks every source until reset; null records a manual none (no name shown). Never a column write."
        avatar_url:
          type: string
          nullable: true
          maxLength: 2048
          format: uri
          description: "New profile photo URL (max 2048): a manual observation; null records a manual none."
        ln_member_id:
          type: string
          nullable: true
          maxLength: 255
          description: Identity edit - re-runs the duplicate flag (a collision flags this row, never a 409).
        ln_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw LinkedIn profile URN (ACoAA...), no spaces; identity edit, re-runs the duplicate flag.
        sn_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw Sales Navigator URN (ACwAA...), no spaces; identity edit, re-runs the duplicate flag.
        recruiter_id:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Raw Recruiter URN (AEMAA...), no spaces; identity edit, re-runs the duplicate flag.
        ln_nickname:
          type: string
          nullable: true
          maxLength: 255
          pattern: ^\S*$
          description: Vanity slug or profile URL (reduced to its axis on write); re-runs the duplicate flag.
        work_email:
          type: string
          nullable: true
          format: email
          description: Identity edit - re-runs the duplicate flag (a collision flags this row, never a 409); stored lowercased.
        personal_email:
          type: string
          nullable: true
          format: email
          description: Identity edit - re-runs the duplicate flag; stored lowercased.
        work_phone_number:
          type: string
          nullable: true
          maxLength: 255
          description: Plain string, E.164 preferred; identity edit on the E.164 twin, re-runs the duplicate flag.
        personal_phone_number:
          type: string
          nullable: true
          maxLength: 255
          description: Plain string, E.164 preferred; identity edit on the E.164 twin, re-runs the duplicate flag.
        linkedin_status:
          type: string
          enum:
            - need_enrichment
            - enrichment_failed
            - no_data
            - blocked
            - ok
          description: Channel status override (need_enrichment | enrichment_failed | no_data | blocked | ok).
        email_status:
          type: string
          nullable: true
          enum:
            - need_search
            - no_data
            - bounced
            - ok
            - catch_all
            - unverified
          description: need_search | no_data | bounced | ok; null = channel not initialized.
        phone_status:
          type: string
          nullable: true
          enum:
            - need_search
            - no_data
            - ok
          description: need_search | no_data | ok; null = channel not initialized.
        company_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^cr_co_
          description: Must exist; the person's company then resolves from the account. null unlinks the company.
        company_name:
          type: string
          nullable: true
          maxLength: 255
          description: A manual observation of a name that is not an account, read when no company_sid links the row; null records a manual none.
        company_ln_id:
          type: string
          nullable: true
          maxLength: 255
          description: A manual observation of the company LinkedIn id, read when no company_sid links the row; null records a manual none.
        tag_sids:
          type: array
          nullable: true
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^cr_tg_
          description: Full-replace of the tag array.
        external_refs:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Free-form CRM sync map, full-replace; keys integration-defined, stored as-is.
    UpdatePersonResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
              description: pt_tb_… - the SINGLE playtable membership; service-managed, changes only via move (create on_duplicate:move / run type move).
            data_source_sid:
              type: string
              nullable: true
            data_source_item_sid:
              type: string
              nullable: true
            company_sid:
              type: string
              nullable: true
            context:
              type: object
              nullable: true
              properties:
                name:
                  type: string
                  nullable: true
                first_name:
                  type: string
                  nullable: true
                  description: The source's own first name when it gave one, else the first word of name.
                picture_url:
                  type: string
                  nullable: true
                  description: A permanent copy over a wire link, the wire link that lasts longest, an expired one counts as none.
                role:
                  type: string
                  nullable: true
                  description: The title at the company (the Sales Navigator wire's position, the enrichment's).
                headline:
                  type: string
                  nullable: true
                  description: The profile line (the regular and Recruiter wires, the inbox participant, the enrichment).
                company:
                  type: object
                  nullable: true
                  properties:
                    sid:
                      type: string
                      nullable: true
                      description: cr_co_… when the person is linked to an account (the account's own resolved context follows); null = a name that is not an account, an import whose company column resolved to none.
                    name:
                      type: string
                      nullable: true
                    domain:
                      type: string
                      nullable: true
                    picture_url:
                      type: string
                      nullable: true
                    ln_id:
                      type: string
                      nullable: true
                      description: "The company's LinkedIn id: the linked account's own, else the person's company id as a source or an edit gave it."
                  required:
                    - sid
                    - name
                    - domain
                    - picture_url
                    - ln_id
                sources:
                  type: object
                  additionalProperties:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                          - data_source_item
                          - file_record
                          - enrichment_cell
                          - participant
                          - connection
                          - profile_read
                          - duplicate_record
                          - manual
                          - legacy_column
                        description: Who said it. A manual word stands until reset; profile_read, enrichment_cell, participant, connection, data_source_item and duplicate_record (a LinkedIn-shaped record another source brought) saw LinkedIn and rank next, newest first; file_record (a CSV or a webhook) and legacy_column (what the dropped column held, backfilled) come last.
                      observed_at:
                        type: string
                        nullable: true
                        description: When the source saw it (ISO 8601); null for a column with no clock.
                    required:
                      - kind
                      - observed_at
                  description: Per resolved key, where it came from and when.
              required:
                - name
                - first_name
                - picture_url
                - role
                - headline
                - company
                - sources
              description: "DERIVED and read-only (CONTEXT_FIELDS_RESEARCH.md section 5): the name, first name, picture, role, headline and company a surface or a model shows next to the row, resolved at read from the observations ledger: a manual word until reset, then the newest LinkedIn-derived observation, then any other. The only place these words are: the row keeps identifiers (phase E, 2026-10-22). Null only on an event payload."
            ln_member_id:
              type: string
              nullable: true
            ln_id:
              type: string
              nullable: true
            sn_id:
              type: string
              nullable: true
            recruiter_id:
              type: string
              nullable: true
            work_email:
              type: string
              nullable: true
            personal_email:
              type: string
              nullable: true
            work_phone_number:
              type: string
              nullable: true
            personal_phone_number:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - ok
                - failed_validation
                - no_contact_data
                - duplicate
                - stoplisted
              description: Service-managed row validity (import validation, stoplist, duplicate detection) - not client-writable.
            duplicate_of_sid:
              type: string
              nullable: true
              description: "While status is duplicate: the PRIMARY row (cr_pp_…) this one is a copy of - one primary per group, re-derived on every recheck, swapped by make_person_primary. Null otherwise."
            duplicate_matched_kind:
              type: string
              nullable: true
              enum:
                - ln_member_id
                - ln_id
                - sn_id
                - recruiter_id
                - email
                - ln_nickname
                - phone
              description: "While status is duplicate: the identifier the check matched on. Null otherwise."
            linkedin_status:
              type: string
              enum:
                - need_enrichment
                - enrichment_failed
                - no_data
                - blocked
                - ok
            email_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - bounced
                - ok
                - catch_all
                - unverified
            phone_status:
              type: string
              nullable: true
              enum:
                - need_search
                - no_data
                - ok
            tag_sids:
              type: array
              nullable: true
              items:
                type: string
            external_refs:
              anyOf:
                - type: object
                  additionalProperties:
                    type: string
                - type: array
                  items: {}
                - {}
              description: Free-form CRM sync map (hubspot_contact_id, …) - keys integration-defined, round-tripped as-is; PHP empty map serialises as [].
            last_enrich_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
            pipeline_stage_sid:
              type: string
              nullable: true
              description: The funnel stage the person is in (cr_ps_...), derived from activity or moved by hand (pipeline_stages.md); null = no stage.
          required:
            - sid
            - team_sid
            - playtable_sid
            - data_source_sid
            - data_source_item_sid
            - company_sid
            - context
            - ln_member_id
            - ln_id
            - sn_id
            - recruiter_id
            - work_email
            - personal_email
            - work_phone_number
            - personal_phone_number
            - status
            - duplicate_of_sid
            - duplicate_matched_kind
            - linkedin_status
            - email_status
            - phone_status
            - tag_sids
            - external_refs
            - last_enrich_at
            - created_at
            - updated_at
            - deleted_at
            - pipeline_stage_sid
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePipelineStageRequest:
      type: object
      description: Request body of `update_pipeline_stage`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New label. A collision with another live stage of the same (team, object) is a 409 duplicate_rejected.
        category:
          type: string
          enum:
            - cold
            - approaching
            - engaging
            - positive
            - nurture
            - negative
            - disqualified
          description: "New funnel bucket. LOCKED on a system stage (key != null): sending a different value there is a 422 validation_failed."
        order:
          type: integer
          minimum: 1
          description: New position, 1..N within its (team, object) pipeline. Siblings recontiguate around it in the same transaction; out of range is a 422. Reordering a person pipeline changes the forward-only rank, so it changes which auto-transitions are allowed to fire.
    UpdatePipelineStageResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Pipeline stage sid (cr_ps_…) - the value people.pipeline_stage_sid / companies.pipeline_stage_sid store.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            object:
              type: string
              enum:
                - person
                - company
              description: "Which pipeline this stage belongs to: person (leads) | company (accounts). Immutable after create."
            name:
              type: string
              description: Stage label (1..255), unique per (team, object) among live rows, case-insensitively.
            category:
              type: string
              enum:
                - cold
                - approaching
                - engaging
                - positive
                - nurture
                - negative
                - disqualified
              description: "Funnel bucket, one of seven: the grouping of the company card and the grid, the chip colour, the funnel analytics and the company derivation (positive > engaging > approaching > nurture > negative > cold; a person on a disqualified stage is not an active member of the account). negative = a real no (Not interested); disqualified = not a target, filtered out (Wrong Decision Maker, Disqualified). Locked on a system stage (key != null)."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the stage (AccessIdentityValue); the seeded system stages carry the system identity.
            key:
              type: string
              nullable: true
              description: "Stable snake_case anchor on SYSTEM stages ('new_contact', 'company_opportunity', …), the target the auto-transition engine resolves; null = a custom stage. key != null is what makes a stage system: locked category, non-deletable. Read-only."
            order:
              type: integer
              nullable: true
              description: Position within its (team, object) pipeline, contiguous 1..N, and the forward-only rank for a person (a target stage is only auto-entered when its order >= the current one). 0 = pulled out of the ordering (a soft-deleted row).
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC; bumped by rename / recategorize / reorder.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - object
            - name
            - category
            - created_by
            - key
            - order
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePlayRequest:
      type: object
      description: Request body of `update_play`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New name of the play (1..255).
        audience:
          description: A new audience, validated like at create; null = the whole tab.
        action:
          type: object
          properties:
            prompt:
              type: string
              nullable: true
              maxLength: 2000
            per_company_limit:
              type: integer
              nullable: true
              minimum: 1
              maximum: 25
            workflow_sid:
              type: string
              minLength: 18
              maxLength: 18
              pattern: ^wf_wf_
              description: "add_to_workflow: the workflow of a play that still waits for one; births the play's manual source there. Picked once: another workflow is refused (422), reset the play (delete_play) to pick again."
            moments:
              type: object
              properties:
                birthday:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
                work_anniversary:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
                job_change:
                  type: object
                  properties:
                    "on":
                      type: boolean
                      description: The moment's switch.
                    do:
                      type: string
                      enum:
                        - send_message
                        - add_to_workflow
                      description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                    template:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: The message, in the workflow template grammar ({{people.first_name}}).
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: the workflow, when the Do is a workflow."
                  required:
                    - "on"
                    - do
                    - template
                    - workflow_sid
              description: "congratulate: one moment's keys move alone, the others stay."
            do:
              type: string
            like:
              type: object
              properties:
                "on":
                  type: boolean
                reaction:
                  type: string
                  enum:
                    - ai
                    - like
                    - celebrate
                    - support
                    - love
                    - insightful
                    - funny
                  description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
            comment:
              type: object
              properties:
                "on":
                  type: boolean
                brief:
                  type: string
                  nullable: true
                  maxLength: 2000
                  description: What the AI writes the comment from; required while on.
            per_person_weekly_cap:
              type: integer
              minimum: 1
              maximum: 14
            sender_profile_sid:
              type: string
              nullable: true
            pages:
              type: array
              nullable: true
              items:
                type: string
          description: A find_people play's prompt and cap, the workflow of a people play that waits for one, or a typed action's keys merged deep over the stored ones; the sources are fixed at birth.
        watch:
          type: object
          nullable: true
          properties:
            profile_days:
              anyOf:
                - type: number
                  enum:
                    - 7
                - type: number
                  enum:
                    - 14
                - type: number
                  enum:
                    - 30
                - type: number
                  enum:
                    - 90
                - {}
              description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
            company_days:
              anyOf:
                - type: number
                  enum:
                    - 30
                - type: number
                  enum:
                    - 90
                - {}
              description: "The company page every N days: 30 | 90; null = not watched."
            posts_days:
              anyOf:
                - type: number
                  enum:
                    - 1
                - type: number
                  enum:
                    - 3
                - type: number
                  enum:
                    - 7
                - {}
              description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
            moments:
              type: boolean
              description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
          description: The whole block, or null for nothing.
        mode:
          type: string
          enum:
            - ask_me
            - automatic
          description: ask_me (the act waits for approval as a task in the Signals feed) | automatic (it goes out by itself).
        cadence:
          type: string
          enum:
            - manual
            - daily
          description: manual switches the play off.
        enabled:
          type: boolean
          description: "The switch: true records the consent (enabled_by, enabled_at) and makes the play due now; false stops the next run, nothing in flight is cancelled."
        daily_credit_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "find_people only: the credits one day may spend; null = no ceiling. 422 on an add_to_workflow play."
    UpdatePlayResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Play sid (pt_pl_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…).
            playtable_sid:
              type: string
              description: "The table the play lives in (pt_tb_…): its tab, and the scope of its audience."
            catalog_key:
              type: string
              nullable: true
              enum:
                - keep_fresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
                - find_people_empty
                - top_up_thin
                - top_up_silent
                - top_up_no_reply
                - top_up_exhausted
                - find_decision_maker
                - reengage_dormant
                - reach_untouched
              description: The playbook entry the row was born from; null = a play saved from a view's filter.
            name:
              type: string
              description: The play's name, 1..255.
            object_type:
              type: string
              enum:
                - people
                - company
              description: "What the audience selects: people, or company (accounts)."
            action_type:
              type: string
              enum:
                - find_people
                - add_to_workflow
                - refresh
                - congratulate
                - on_job_change
                - engage_posts
                - on_website_visit
              description: "find_people (a company audience); every other kind runs on a people audience: add_to_workflow, refresh (Keep data fresh), congratulate, on_job_change, engage_posts, on_website_visit."
            action:
              anyOf:
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      description: Who to find at each account ("owner, founder, VP and up"); planned once into a Sales Navigator filter by the play's source. null = everyone the page gives.
                    per_company_limit:
                      type: integer
                      nullable: true
                      description: People taken per account, 1..25; null = the whole first page.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The play's own find_people source (ds_sc_…), born at the first run that had accounts; its queue and funnel are read with get_data_source. null until then.
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      description: The workflow the audience enters (wf_wf_…); null while the play waits for one (picked once, with update_play), and fixed from then on.
                    workflow_source_sid:
                      type: string
                      nullable: true
                      description: The play's own manual source in that workflow (wf_sr_…), born when the workflow is picked; its entry counters are read with search_workflow_sources.
                  required:
                    - workflow_sid
                    - workflow_source_sid
                - type: object
                  properties:
                    moments:
                      type: object
                      properties:
                        birthday:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        work_anniversary:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                        job_change:
                          type: object
                          properties:
                            "on":
                              type: boolean
                              description: The moment's switch.
                            do:
                              type: string
                              enum:
                                - send_message
                                - add_to_workflow
                              description: "While on: a message (the template, sent as the person's connected sender profile) or the workflow the person enters."
                            template:
                              type: string
                              nullable: true
                              maxLength: 2000
                              description: The message, in the workflow template grammar ({{people.first_name}}).
                            workflow_sid:
                              type: string
                              nullable: true
                              description: "wf_wf_…: the workflow, when the Do is a workflow."
                          required:
                            - "on"
                            - do
                            - template
                            - workflow_sid
                      description: A switch per moment with its own Do under it; a kind absent is off.
                  required:
                    - moments
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - remove_from_workflows
                        - move_to_workflow
                      description: For a person in a workflow whose title or company moved.
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: where move_to_workflow moves the person (required then)."
                  required:
                    - do
                    - workflow_sid
                - type: object
                  properties:
                    like:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        reaction:
                          type: string
                          enum:
                            - ai
                            - like
                            - celebrate
                            - support
                            - love
                            - insightful
                            - funny
                          description: ai = the AI reads the post and picks one of the six; else always this one. One reaction a post, never changed later.
                      required:
                        - "on"
                        - reaction
                    comment:
                      type: object
                      properties:
                        "on":
                          type: boolean
                        brief:
                          type: string
                          nullable: true
                          maxLength: 2000
                          description: What the AI writes the comment from; required while on.
                      required:
                        - "on"
                        - brief
                    per_person_weekly_cap:
                      type: integer
                      minimum: 1
                      maximum: 14
                      description: At most this many acts a week per person.
                    sender_profile_sid:
                      type: string
                      nullable: true
                      description: "ub_sp_…: who acts on a person connected to no sender profile (the connected one acts otherwise; the social workspace is the team's); null = the team's first that can."
                  required:
                    - like
                    - comment
                    - per_person_weekly_cap
                    - sender_profile_sid
                - type: object
                  properties:
                    do:
                      type: string
                      enum:
                        - pause_and_ask
                        - add_to_workflow
                      description: "On a visit of a key page or a form: pause the journey and ask, or the workflow named."
                    workflow_sid:
                      type: string
                      nullable: true
                      description: "wf_wf_…: required when the Do is a workflow."
                    pages:
                      type: array
                      nullable: true
                      items:
                        type: string
                      description: Path prefixes of the team's site (/pricing) that count; null = every visit the snippet reports.
                  required:
                    - do
                    - workflow_sid
                    - pages
                - type: object
                  properties: {}
                  description: "Keep data fresh acts on nothing: the refresh of what it watches is the deed."
              description: "The action's parameters, the shape of its action_type: the sids of the sources a find_people or add_to_workflow play owns; the moments of a congratulate play; the Do of on_job_change and on_website_visit; the like, the comment and the weekly cap of engage_posts; {} for refresh."
            audience:
              description: "The tab's own filter AST (the §4.18 tree a saved view carries: {field: \"signals\", op: {in: [\"no_engagement\"]}}, pipeline_stage_category, tag_sids, record.<slug> cells, and/or or and); null = the whole tab."
            watch:
              type: object
              nullable: true
              properties:
                profile_days:
                  anyOf:
                    - type: number
                      enum:
                        - 7
                    - type: number
                      enum:
                        - 14
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The LinkedIn profile every N days: 7 | 14 | 30 | 90; null = not watched."
                company_days:
                  anyOf:
                    - type: number
                      enum:
                        - 30
                    - type: number
                      enum:
                        - 90
                    - {}
                  description: "The company page every N days: 30 | 90; null = not watched."
                posts_days:
                  anyOf:
                    - type: number
                      enum:
                        - 1
                    - type: number
                      enum:
                        - 3
                    - type: number
                      enum:
                        - 7
                    - {}
                  description: "The person's posts every N days: 1 | 3 | 7; null = not watched."
                moments:
                  type: boolean
                  description: The network's moments (birthdays, work anniversaries, job changes) through the sender profiles' catch-up feed, daily, free.
              required:
                - profile_days
                - company_days
                - posts_days
                - moments
              description: What the play keeps refreshed and how often; null = nothing (2026-10-13).
            cadence:
              type: string
              enum:
                - manual
                - daily
              description: "manual: runs on run_play; daily: runs by itself every day while enabled."
            mode:
              type: string
              enum:
                - ask_me
                - automatic
              description: "ask_me: the act waits for approval as a task in the Signals feed; automatic: it goes out by itself. The plays that act are born asking (2026-10-13)."
            enabled:
              type: boolean
              description: The switch of a daily play; a manual play is always false.
            enabled_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Who gave the consent (switched the play on).
            enabled_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when."
            daily_credit_limit:
              type: integer
              nullable: true
              description: "The plays that spend (find_people, and a watching play's reads): the credits one day may spend; null = no ceiling (the queue's room and the 500-row cap still bound a run). 422 on add_to_workflow."
            last_run_at:
              type: string
              nullable: true
              description: ISO 8601 UTC.
            last_run_counts:
              type: object
              nullable: true
              properties:
                matched:
                  type: integer
                  minimum: 0
                  description: Rows the audience matched at the run (the tab's count under the filter).
                acted:
                  type: integer
                  minimum: 0
                  description: Accounts appended to the queue, or people entered or re-entered.
                skipped:
                  type: integer
                  minimum: 0
                  description: "Left alone: already queued or searched, in flight, held at the door, past the ceiling or the 500-row cap."
                credits:
                  type: integer
                  minimum: 0
                  description: "What the run committed: the walk's estimate for the accounts appended (one credit per account); 0 for an add_to_workflow play."
              required:
                - matched
                - acted
                - skipped
                - credits
              description: What the last run did; null before the first run.
            next_run_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC: when the daily sweep runs it next; null on a manual or switched-off play."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live.
          required:
            - sid
            - team_sid
            - playtable_sid
            - catalog_key
            - name
            - object_type
            - action_type
            - action
            - watch
            - cadence
            - mode
            - enabled
            - enabled_by
            - enabled_at
            - daily_credit_limit
            - last_run_at
            - last_run_counts
            - next_run_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePlaytableFieldRequest:
      type: object
      description: Request body of `update_playtable_field`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New display label (1..255); the slug never changes.
        type:
          type: string
          enum:
            - scalar_text
            - scalar_number
            - scalar_currency
            - scalar_date
            - scalar_url
            - scalar_checkbox
            - scalar_select
            - scalar_multiselect
            - scalar_image
          description: "Type change of a scalar column (scalar to scalar only): every cell is re-cast, unconvertible values are flagged is_not_valid, the ES slot moves. Widgets and actions never convert."
        payload:
          anyOf:
            - type: object
              properties:
                formula:
                  type: string
                  nullable: true
                  maxLength: 8192
                  description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                template:
                  type: string
                  nullable: true
                  maxLength: 8192
                  description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                nl_formula:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                options:
                  type: array
                  nullable: true
                  items:
                    type: string
                  minItems: 1
                  description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                currency:
                  type: string
                  nullable: true
                  pattern: ^[A-Z]{3}$
                  description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                option_colors:
                  type: object
                  nullable: true
                  additionalProperties:
                    type: string
                    pattern: ^#[0-9a-f]{6}$
                  description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
              required:
                - formula
                - template
                - nl_formula
                - options
                - currency
                - option_colors
            - type: object
              properties: {}
              additionalProperties: false
              description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
            - type: object
              properties:
                workflow_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^wf_wf_
                  description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
              required:
                - workflow_sid
              additionalProperties: false
            - type: object
              properties:
                stats_view:
                  type: string
                  enum:
                    - all
                    - last
                    - select
                  description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                sender_profile_sid:
                  type: string
                  nullable: true
                  minLength: 18
                  maxLength: 18
                  pattern: ^ub_sp_
                  description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
              required:
                - stats_view
                - sender_profile_sid
              additionalProperties: false
            - type: object
              properties:
                prompt:
                  type: string
                  minLength: 1
                  maxLength: 8192
                  description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                model:
                  type: string
                  minLength: 1
                  maxLength: 128
                  description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                output:
                  type: string
                  enum:
                    - text
                    - number
                    - select
                    - json
                  description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                options:
                  type: array
                  nullable: true
                  items:
                    type: string
                  minItems: 1
                  description: Required (min 1) when output=select; null otherwise.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                web_search:
                  type: boolean
                  description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
              required:
                - prompt
                - model
                - output
                - options
                - output_mapping
            - type: object
              properties:
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      tool_sid:
                        type: string
                        minLength: 1
                        description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                      params:
                        type: object
                        additionalProperties: {}
                        description: Tool params; string values may be Twig templates over the same variable namespace.
                    required:
                      - tool_sid
                      - params
                  maxItems: 10
                  description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                stop_on_first:
                  type: boolean
                  description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                verify:
                  type: object
                  nullable: true
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                  required:
                    - tool_sid
                    - params
                  description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                accept_catch_all:
                  type: boolean
                  description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
              required:
                - steps
                - stop_on_first
                - output_mapping
            - type: object
              properties:
                tool_sid:
                  type: string
                  minLength: 1
                  description: gtm-api tool registry sid (external format); existence + price validated at save.
                params:
                  type: object
                  additionalProperties: {}
                  description: Tool params; string values may be Twig templates over the same variable namespace.
                output_mapping:
                  type: array
                  nullable: true
                  items:
                    type: object
                    properties:
                      path:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                      target:
                        type: string
                        minLength: 1
                        maxLength: 128
                        description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                    required:
                      - path
                      - target
                  maxItems: 20
                  description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
              required:
                - tool_sid
                - params
                - output_mapping
            - type: object
              properties:
                prompt:
                  type: string
                  nullable: true
                  maxLength: 2000
                  description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                per_company_limit:
                  type: integer
                  minimum: 1
                  maximum: 25
                  description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                data_source_sid:
                  type: string
                  nullable: true
                  description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                qualify:
                  type: object
                  nullable: true
                  properties:
                    "on":
                      type: boolean
                      description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                    criterion:
                      type: string
                      nullable: true
                      minLength: 1
                      maxLength: 2000
                      description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                  required:
                    - "on"
                    - criterion
                  additionalProperties: false
                  description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
              required:
                - prompt
                - per_company_limit
                - data_source_sid
          description: Full replacement; shape must still match the row's immutable type.
        config:
          type: object
          properties:
            auto_run:
              type: boolean
              description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
            run_condition:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                        is_null:
                          type: boolean
                        contains:
                          type: string
                          minLength: 1
                        not_contains:
                          type: string
                          minLength: 1
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                        starts_with:
                          type: string
                          minLength: 1
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
            nl_condition:
              type: string
              nullable: true
              maxLength: 2048
              description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
            daily_credit_limit:
              type: integer
              nullable: true
              minimum: 0
              exclusiveMinimum: true
              description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
            preset_sid:
              type: string
              nullable: true
              description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
          required:
            - auto_run
            - run_condition
            - nl_condition
            - daily_credit_limit
            - preset_sid
          description: Full replacement; action fields only (non-default on scalar/widget → 422).
    UpdatePlaytableFieldResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object grid this field belongs to: people or company rows. Fixed at create."
            name:
              type: string
              description: Display label, freely editable.
            slug:
              type: string
              description: Template-variable name ({{record.<slug>}}); unique per playtable, IMMUTABLE after create.
            category:
              type: string
              enum:
                - scalar
                - widget
                - action
              description: scalar = data column (optional free formula) | widget = live CRM projection, no cells | action = paid executor. Derived from the type prefix - never user-supplied.
            type:
              type: string
              enum:
                - scalar_text
                - scalar_number
                - scalar_currency
                - scalar_date
                - scalar_url
                - scalar_checkbox
                - scalar_select
                - scalar_multiselect
                - scalar_image
                - widget_data_source
                - widget_tags
                - widget_active_workflows
                - widget_notes
                - widget_company
                - widget_linkedin_id
                - widget_linkedin_channel
                - widget_work_email
                - widget_personal_email
                - widget_email_channel
                - widget_phones
                - widget_phone_channel
                - widget_last_touch
                - widget_activity
                - widget_deal_size
                - widget_website
                - widget_people_summary
                - widget_ai_sdr
                - action_ai_research
                - action_waterfall
                - action_gtm_tool
                - action_find_people
              description: "The category derives from the prefix. Scalar and the generic action types fit both grids; action_find_people is company-only. Widgets: data_source, tags, last_touch, activity on both; deal_size, website, people_summary company-only; the rest people-only."
            payload:
              anyOf:
                - type: object
                  properties:
                    formula:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "CEL expression, NO {{ }} braces (those are for templates). Reference paths extract typed values: record.<slug>(.<seg>|[N])* - e.g. \"record.enrich.contact_info.websites[0].url\" (extraction column - the \"Add as column\" case; backfills all rows on save, re-derives on every source run; absent path → empty cell), and on a people grid company.record.<slug>(.<seg>|[N])* - the linked account's cell in this playtable (a Companies-tab column; on the company grid the account is the row itself). A company.record reference is checked against the Companies tab at save, backfilled the same way, and is NOT re-derived when the account's cell changes later (no cross-object dependency: a snapshot until the column's next recalc). Full CEL computes: operators, ?: conditions, has(), string concat - e.g. 'record.employees > 50 ? 100 : 40'. Syntax errors 422 at save; runtime failures land as cell error_msg. Evaluated backend-side; null = manually-entered column. Setting/changing it recomputes EVERY cell including pinned ones. When template is set, this is server-GENERATED from it - send the template instead of hand-writing CEL."
                    template:
                      type: string
                      nullable: true
                      maxLength: 8192
                      description: "The unified authoring source - prose + {{record.<slug>…}} / {{people.<attr>}} / {{company.<attr>}} / {{company.record.<slug>…}} variables, as in a flow-node message: \"Hey {{people.first_name}}, saw {{company.name}}!\". record.<slug> is THIS tab's columns only ({{record.full_name}} is refused unless a column has that slug); people.<attr> the person's catalog (full_name, first_name, company_name, ln_nickname, work_email, timezone, pipeline_stage_name...); company.<attr> the linked account's (name, domain, website, ln_nickname, people_count...); company.record.<slug> the company tab's columns. An attribute outside the catalogs is refused at save (unknown template variable people.title); people.role and people.headline are derived (the title and the profile line the enrichment, the search record or the inbox observed), and {{record.data_source.position}} still reads the raw record. Compiled into formula on every save: absent value → empty string; a LONE variable ({{record.enrich.company.employees}}) → the bare typed reference (numbers stay numbers); stray braces → 422 on payload.template. Round-trips verbatim. null = formula authored as CEL; template:\"\" clears both."
                    nl_formula:
                      type: string
                      nullable: true
                      maxLength: 2048
                      description: Natural-language source of truth the formula was compiled from - agents edit THIS and regenerate formula.
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Option labels for scalar_select / scalar_multiselect (min 1); null for every other scalar type.
                    currency:
                      type: string
                      nullable: true
                      pattern: ^[A-Z]{3}$
                      description: ISO-4217 code (e.g. USD) for scalar_currency only; null = render default USD; null for every other scalar type.
                    option_colors:
                      type: object
                      nullable: true
                      additionalProperties:
                        type: string
                        pattern: ^#[0-9a-f]{6}$
                      description: "Option name → #rrggbb hex for scalar_select / scalar_multiselect only; keys ⊆ options (min 1 entry - send null instead of an empty map)."
                  required:
                    - formula
                    - template
                    - nl_formula
                    - options
                    - currency
                    - option_colors
                - type: object
                  properties: {}
                  additionalProperties: false
                  description: Always {} - widget rendering is type-driven (widget_active_workflows and the two channel widgets carry their own knobs, below).
                - type: object
                  properties:
                    workflow_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^wf_wf_
                      description: "null = All workflows: a cell counts the lead's live journeys by state. A wf_wf_ sid = Specific workflow: the column is pinned to it, a cell shows the lead's record there, finished too; a live workflow (422 relation_not_found). A pin outlives its workflow."
                  required:
                    - workflow_sid
                  additionalProperties: false
                - type: object
                  properties:
                    stats_view:
                      type: string
                      enum:
                        - all
                        - last
                        - select
                      description: "Whose numbers the cell shows: all = every sender profile's facts summed, no face; last = the sender profile that touched the person on that channel last, its face and counters (the default); select = the one named by sender_profile_sid."
                    sender_profile_sid:
                      type: string
                      nullable: true
                      minLength: 18
                      maxLength: 18
                      pattern: ^ub_sp_
                      description: "The sender profile of a select view (ub_sp_): required under select, null otherwise (422 validation_failed). It must name a live sender profile of the team (422 relation_not_found); a deleted pick is kept until another is set."
                  required:
                    - stats_view
                    - sender_profile_sid
                  additionalProperties: false
                - type: object
                  properties:
                    prompt:
                      type: string
                      minLength: 1
                      maxLength: 8192
                      description: "Twig-templated research instruction; the template's variables, an unknown one 422. What the source found on a person (the role, the location) is in the Data source cell: {{record.data_source}} (its slug on a new table) reads it whole."
                    model:
                      type: string
                      minLength: 1
                      maxLength: 128
                      description: "'auto' (gtm-api routes the call) or a concrete gtm-api model id; validated against the gtm-api registry at save."
                    output:
                      type: string
                      enum:
                        - text
                        - number
                        - select
                        - json
                      description: "Cell shape: text | number (non-numeric model answer → cell error) | select (one of payload.options) | json (extract values into columns via extraction formulas record.<slug>.<path>; push onto people/company attributes via output_mapping)."
                    options:
                      type: array
                      nullable: true
                      items:
                        type: string
                      minItems: 1
                      description: Required (min 1) when output=select; null otherwise.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Project a 'json' result onto people/company attributes, fill-if-empty (max 20); null = no attribute writes. Columns pull via extraction formulas instead.
                    web_search:
                      type: boolean
                      description: "Default false: the model answers with the vendor's server-side web search on. A per-model capability: 422 relation_not_found at save, and web_search_not_supported on a preview, for a model without it."
                  required:
                    - prompt
                    - model
                    - output
                    - options
                    - output_mapping
                - type: object
                  properties:
                    steps:
                      type: array
                      items:
                        type: object
                        properties:
                          tool_sid:
                            type: string
                            minLength: 1
                            description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                          params:
                            type: object
                            additionalProperties: {}
                            description: Tool params; string values may be Twig templates over the same variable namespace.
                        required:
                          - tool_sid
                          - params
                      maxItems: 10
                      description: 1..10 ordered gtm-api tool steps, first accepted result wins; pass [] when config.preset_sid materializes them server-side (never both).
                    stop_on_first:
                      type: boolean
                      description: true (default) = stop at the first step returning a non-empty accepted result; false = run all, first non-empty wins.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Winning step's result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                    verify:
                      type: object
                      nullable: true
                      properties:
                        tool_sid:
                          type: string
                          minLength: 1
                          description: "The step: a gtm-api tool registry sid, an integration-platform step (in:{provider}.{operation}, in:tool.{sid}) or the row itself (row:people.work_email: the row's own address, free, verified unless already ok; people, once). Price validated at save."
                        params:
                          type: object
                          additionalProperties: {}
                          description: Tool params; string values may be Twig templates over the same variable namespace.
                      required:
                        - tool_sid
                        - params
                      description: One in:{provider}.email.verify step on every email a finder returns, no params. valid accepts and ends the chain, so does catch_all while accept_catch_all is on; invalid, unknown or a failure rejects, the next finder runs. null = none, first found wins.
                    accept_catch_all:
                      type: boolean
                      description: "true (default): a catch-all address is accepted the moment the verifier says so and the chain stops there. false = catch-all emails are rejected like invalid ones (safe to send only) and the next finder runs. Meaningful only with verify set."
                  required:
                    - steps
                    - stop_on_first
                    - output_mapping
                - type: object
                  properties:
                    tool_sid:
                      type: string
                      minLength: 1
                      description: gtm-api tool registry sid (external format); existence + price validated at save.
                    params:
                      type: object
                      additionalProperties: {}
                      description: Tool params; string values may be Twig templates over the same variable namespace.
                    output_mapping:
                      type: array
                      nullable: true
                      items:
                        type: object
                        properties:
                          path:
                            type: string
                            minLength: 1
                            maxLength: 512
                            description: JSON path into the tool/model result, e.g. $.email or $.techs[0].name.
                          target:
                            type: string
                            minLength: 1
                            maxLength: 128
                            description: "Entity-attribute target ONLY: people.<attr> or company.<attr> (writable-attribute registries; fill-if-empty at projection); validated at save. No record.<slug> targets: columns pull via extraction formulas (record.<slug>.<path>), never via push mapping."
                        required:
                          - path
                          - target
                      maxItems: 20
                      description: Tool result → people/company attributes, fill-if-empty (max 20); null = no attribute writes.
                  required:
                    - tool_sid
                    - params
                    - output_mapping
                - type: object
                  properties:
                    prompt:
                      type: string
                      nullable: true
                      maxLength: 2000
                      description: Who to find at each company, in words; null = everyone there. With data_source_sid null on create the server births a find_people source; a new text on update births a new search and parks the old. 422 prohibited beside a picked data_source_sid.
                    per_company_limit:
                      type: integer
                      minimum: 1
                      maximum: 25
                      description: People taken per company, 1..25 (one search page, by relevance). Default 1. Mirrored onto the column's own search; read from a picked one.
                    data_source_sid:
                      type: string
                      nullable: true
                      description: The find_people source the cells search (ds_sc_). null on create = the server makes one for the column (the sid comes back). A sid = a find_people search of the SAME table, as is (422 other_table elsewhere, relation_not_found when gone). Never null stored.
                    qualify:
                      type: object
                      nullable: true
                      properties:
                        "on":
                          type: boolean
                          description: The switch. `on` with no criterion is refused (422 on qualify.criterion, rule required_if).
                        criterion:
                          type: string
                          nullable: true
                          minLength: 1
                          maxLength: 2000
                          description: Who passes, in the user's words ("a decision maker at a marketing agency, not a freelancer"). Trimmed; null while the check is off.
                      required:
                        - "on"
                        - criterion
                      additionalProperties: false
                      description: "Check on save: {on, criterion} the column's own search takes at every save, judging the people the walk finds before they land (data_sources.qualify); null or absent = no check. 422 prohibited beside a picked data_source_sid (it has its own gate)."
                  required:
                    - prompt
                    - per_company_limit
                    - data_source_sid
              description: Per-type payload; the discriminator is the row's type column, not an inner key - the shape must match type (scalar / widget / active_workflows / channel / ai_research / waterfall / gtm_tool / find_people branches) or the save fails with 422.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: "Action auto-fires when a row enters the table / the cell is empty (paid: empty→queued only). Default false."
                run_condition:
                  anyOf:
                    - type: object
                      properties:
                        and:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - and
                      additionalProperties: false
                    - type: object
                      properties:
                        or:
                          type: array
                          items:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          minItems: 1
                          maxItems: 20
                      required:
                        - or
                      additionalProperties: false
                    - type: object
                      properties:
                        not:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - not
                      additionalProperties: false
                    - type: object
                      properties:
                        any:
                          type: object
                          properties:
                            path:
                              type: string
                              minLength: 1
                              description: Array-valued path - the only way to reach inside an array.
                            where:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - path
                            - where
                          additionalProperties: false
                      required:
                        - any
                      additionalProperties: false
                    - type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                          description: "Namespaced path: record.<slug> or a built-in object attribute; element-relative inside any.where."
                        op:
                          type: object
                          properties:
                            eq:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            ne:
                              anyOf:
                                - type: string
                                - type: number
                                - type: boolean
                            in:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            nin:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                              minItems: 1
                              maxItems: 100
                            gt:
                              anyOf:
                                - type: number
                                - type: string
                            gte:
                              anyOf:
                                - type: number
                                - type: string
                            lt:
                              anyOf:
                                - type: number
                                - type: string
                            lte:
                              anyOf:
                                - type: number
                                - type: string
                            is_null:
                              type: boolean
                            contains:
                              type: string
                              minLength: 1
                            not_contains:
                              type: string
                              minLength: 1
                            contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            not_contains_any:
                              type: array
                              items:
                                type: string
                                minLength: 1
                              minItems: 1
                              maxItems: 50
                            starts_with:
                              type: string
                              minLength: 1
                          additionalProperties: false
                      required:
                        - field
                        - op
                      additionalProperties: false
                    - {}
                  description: Per-row filter-AST gate (§4.18 atoms, strict mode); unmet → cell status run_condition_not_met; null = always run.
                nl_condition:
                  type: string
                  nullable: true
                  maxLength: 2048
                  description: Natural-language source of truth for run_condition - agents edit THIS and regenerate the AST.
                daily_credit_limit:
                  type: integer
                  nullable: true
                  minimum: 0
                  exclusiveMinimum: true
                  description: Max credits this field may spend per UTC day (int > 0, enforced at run time); null = no cap.
                preset_sid:
                  type: string
                  nullable: true
                  description: gtm-api preset sid (external) that materializes waterfall steps at save; action_waterfall only, mutually exclusive with hand-built steps. null otherwise.
              required:
                - auto_run
                - run_condition
                - nl_condition
                - daily_credit_limit
                - preset_sid
            backfill:
              type: object
              nullable: true
              properties:
                status:
                  type: string
                  enum:
                    - queued
                    - running
                    - done
                    - failed
                scanned:
                  type: integer
                  minimum: 0
                  description: Objects the scan has visited so far.
                total:
                  type: integer
                  nullable: true
                  minimum: 0
                  description: The scan size, known once the job starts (null while queued).
                queued_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the column started owing its backfill."
                started_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when the job took it."
                finished_at:
                  type: string
                  nullable: true
                  description: "ISO 8601 UTC: when it ended, done or failed."
                error:
                  type: string
                  nullable: true
                  description: A reason token (backfill_failed) on failed, never an exception message.
              required:
                - status
                - scanned
                - total
                - queued_at
                - started_at
                - finished_at
                - error
              description: The formula column's backfill ledger (see PlaytableFieldBackfill); null on a column with no formula.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - slug
            - category
            - type
            - payload
            - config
            - backfill
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePlaytableFieldValueRequest:
      type: object
      description: Request body of `update_playtable_field_value`.
      properties:
        value:
          type: string
          nullable: true
          description: New cell value (canonical string; per-type parsing lives in the field's ES mapping). null clears the value - the cell finalizes as done with value=null (never empty). Only mutable field - an empty PATCH returns 422 nothing_to_update.
    UpdatePlaytableFieldValueResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            object_sid:
              type: string
            playtable_field_sid:
              type: string
            value:
              type: string
              nullable: true
            is_value_from_formula:
              type: boolean
            original_value:
              type: string
              nullable: true
              description: "The system-produced value the FIRST manual overwrite snapshotted, what reset restores; null unless is_overwritten. The list surface nulls it like meta: read it on get, update, write and reset."
            is_overwritten:
              type: boolean
              description: "The current value is a manual write over a system-produced one: the edited marker, and the one state reset accepts."
            is_not_valid:
              type: boolean
              description: A manually written value that could not be converted to the column's type (text in a number column), stored raw and flagged; system writers coerce or null instead.
            status:
              type: string
              enum:
                - empty
                - queued
                - running
                - done
                - error
                - run_condition_not_met
            cost:
              type: number
              nullable: true
            provider_sid:
              type: string
              nullable: true
            meta:
              type: object
              nullable: true
              properties:
                run_sid:
                  type: string
                  nullable: true
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      step_index:
                        type: number
                      tool_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - success
                          - failed
                          - skipped
                      cost:
                        type: number
                      error:
                        type: string
                        nullable: true
                      finished_at:
                        type: string
                        nullable: true
                      verdict:
                        type: string
                        nullable: true
                      email:
                        type: string
                        nullable: true
                    required:
                      - step_index
                      - tool_sid
                      - status
                      - cost
                      - error
                      - finished_at
              required:
                - run_sid
                - steps
            error_msg:
              type: string
              nullable: true
            finished_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - object_sid
            - playtable_field_sid
            - value
            - is_value_from_formula
            - original_value
            - is_overwritten
            - is_not_valid
            - status
            - cost
            - provider_sid
            - meta
            - error_msg
            - finished_at
            - created_at
            - updated_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePlaytableRequest:
      type: object
      description: Request body of `update_playtable`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New table name (1..255), unique per team.
        description:
          type: string
          nullable: true
          maxLength: 2000
          description: null resets the description.
        config:
          type: object
          properties:
            auto_run:
              type: boolean
              description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
          required:
            - auto_run
          description: Full-replace of the config Value.
        agent_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_ag_
          description: Pick the AI SDR for this table (ub_ag_…); null = back to the team's default. Reaches the table's open threads at their next turn.
    UpdatePlaytableResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this table (ub_ag_…, block 10 step 10.2): the agent that works every thread of its people, every setting on the agent itself (its Brief, goal, link, scenarios: update_agent). Null = the team's default agent, whichever it is. The table's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            company_default_view_sid:
              type: string
              description: pt_vw_… default view of the companies tab; auto-created with the table, read-only.
            people_default_view_sid:
              type: string
              description: pt_vw_… default view of the people tab; auto-created with the table, read-only.
            config:
              type: object
              properties:
                auto_run:
                  type: boolean
                  description: When true, action fields fire automatically on rows entering the table (empty→queued). Default false.
              required:
                - auto_run
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - agent_sid
            - company_default_view_sid
            - people_default_view_sid
            - config
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdatePlaytableViewRequest:
      type: object
      description: Request body of `update_playtable_view`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New view name; unique per (playtable, object_type).
        columns:
          type: array
          items:
            type: object
            properties:
              column_type:
                type: string
                enum:
                  - group
                  - field
                  - field_group
                description: "'field' = custom field of the table (column_value = pt_fd_ sid); 'group' = built-in attribute group."
              column_value:
                type: string
                nullable: true
                minLength: 1
                description: "For 'field': pt_fd_ sid of a field on the SAME playtable + object_type (422 otherwise). For 'group': attribute-group key. Absent or null for 'field_group' (the band carries column_values instead)."
              column_values:
                type: array
                nullable: true
                items:
                  type: object
                  properties:
                    column_value:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^pt_fd_
                      description: "A field of the band: pt_fd_ sid on the SAME playtable + object_type."
                    width:
                      type: integer
                      minimum: 40
                      maximum: 1000
                      description: Member column width in px, 40..1000. Default 200.
                    is_visible:
                      type: boolean
                      description: Default true.
                  required:
                    - column_value
                  additionalProperties: false
                minItems: 2
                maxItems: 20
                description: "'field_group' only (null elsewhere): the band's members, 2..20 fields in grid order (a band is one block in the header reorder)."
              is_collapsed:
                type: boolean
                nullable: true
                description: "'field_group' only (null elsewhere): the band folded to its tag. Default false."
              column_name:
                type: string
                nullable: true
                maxLength: 255
                description: Header label override; omit or null = catalog / field name.
              is_pinned:
                type: boolean
                description: Pin to the left grid edge. Default false.
              width:
                type: integer
                minimum: 40
                maximum: 1000
                description: Column width in px, 40..1000. Default 200.
              is_visible:
                type: boolean
                description: Default true; hidden columns keep their slot and order.
            required:
              - column_type
            additionalProperties: false
          description: Full replace of the columns layout (not a merge).
        sort:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                minLength: 1
                maxLength: 255
                description: Built-in object column ("created_at", "full_name") or "record.<slug>"; resolved against the view object_type.
              direction:
                type: string
                enum:
                  - asc
                  - desc
                description: "'asc' | 'desc'."
            required:
              - field
              - direction
            additionalProperties: false
          maxItems: 3
          description: Full replace of the sort order; max 3 entries.
        filter:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar equality. eq: null is rejected - use is_null."
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar inequality. ne: null is rejected - use is_null."
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value in list, 1..100 scalars.
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value not in list, 1..100 scalars.
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Greater than; string operand = ISO 8601 datetime.
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                      description: ">= bound; pair with lte in the SAME op for a range."
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Less than; string operand = ISO 8601 datetime.
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                      description: <= bound; pair with gte in the SAME op for a range.
                    is_null:
                      type: boolean
                      description: true = absent-or-null; false = present and non-null.
                    contains:
                      type: string
                      minLength: 1
                      description: Case-insensitive substring match.
                    not_contains:
                      type: string
                      minLength: 1
                      description: Negated case-insensitive substring match.
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when ANY is a ci substring.
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when NONE is a ci substring.
                    starts_with:
                      type: string
                      minLength: 1
                      description: Case-insensitive prefix match.
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
            - {}
          description: Full replace of the filter AST; null clears it (whole tab). Retargets live audiences on the next poll cycle.
    UpdatePlaytableViewResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: View sid (pt_vw_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            playtable_sid:
              type: string
              description: Owner playtable (pt_tb_…).
            object_type:
              type: string
              enum:
                - people
                - company
              description: "Object tab the view lenses: people | company. Fixed at create."
            name:
              type: string
              description: View name; unique per (playtable, object_type) among live rows.
            columns:
              type: array
              items:
                type: object
                properties:
                  column_type:
                    type: string
                    enum:
                      - group
                      - field
                      - field_group
                    description: "'field' = custom field of the table; 'group' = built-in attribute group of the object."
                  column_value:
                    type: string
                    nullable: true
                    description: "For 'field': pt_fd_ sid of the custom field. For 'group': built-in attribute-group key of the object_type. null for 'field_group'."
                  column_values:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        column_value:
                          type: string
                        width:
                          type: integer
                        is_visible:
                          type: boolean
                      required:
                        - column_value
                        - width
                        - is_visible
                    description: "'field_group' only: the band's member fields in grid order."
                  is_collapsed:
                    type: boolean
                    nullable: true
                    description: "'field_group' only: the band folded to its tag."
                  column_name:
                    type: string
                    nullable: true
                    description: Header label override; null = catalog / field name.
                  is_pinned:
                    type: boolean
                    description: Pinned to the left edge of the grid.
                  width:
                    type: number
                    description: Column width in px (40..1000).
                  is_visible:
                    type: boolean
                    description: Hidden columns keep their slot and order.
                required:
                  - column_type
                  - column_value
                  - column_name
                  - is_pinned
                  - width
                  - is_visible
              description: Ordered left→right; [] = base-attribute catalog fallback.
            sort:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: Built-in object column ("created_at", "full_name") or "record.<slug>" custom-field reference.
                  direction:
                    type: string
                    enum:
                      - asc
                      - desc
                    description: "'asc' | 'desc'."
                required:
                  - field
                  - direction
              description: Applied in array order; max 3 entries.
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: 'Namespaced path: built-in object attribute or "record.<slug>" of the same tab; element-relative inside any.where.'
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Stored filter AST (§4.18-atom tree); null = whole tab.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the view (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the view; null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - name
            - columns
            - sort
            - filter
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateTagRequest:
      type: object
      description: Request body of `update_tag`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New label; re-checked case-insensitively against live tags - 409 duplicate_rejected on collision.
        color:
          type: string
          nullable: true
          minLength: 7
          maxLength: 7
          pattern: ^#[0-9a-f]{6}$
          description: New chip color "#rrggbb" (lowercase hex); null resets to the client default palette.
    UpdateTagResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Tag sid (cr_tg_…) - the value objects store in tag_sids[].
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            name:
              type: string
              description: Label text, stored as entered (original casing); unique per team case-insensitively among live rows.
            color:
              type: string
              nullable: true
              description: Chip color "#rrggbb" (lowercase hex); null = client default palette.
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that created the tag (AccessIdentityValue).
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete).
          required:
            - sid
            - team_sid
            - name
            - color
            - created_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateWorkflowRequest:
      type: object
      description: Request body of `update_workflow`.
      properties:
        playtable_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_tb_
          description: Move the workflow to another home playtable (draft only; the sources and step references must still resolve at publish).
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New campaign name (1..255), unique per team.
        description:
          type: string
          nullable: true
          maxLength: 2000
          description: null resets the description.
        draft_steps:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    nullable: true
                    description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_message
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Message template (same namespaces as all templates).
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_inmail
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    nullable: true
                    maxLength: 200
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_visit_profile
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_endorse_skills
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  skills_count:
                    type: integer
                    minimum: 1
                    maximum: 10
                    description: Endorse the person's top N listed skills, 1..10.
                required:
                  - type
                  - skills_count
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_withdraw_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_like_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_comment_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  comment:
                    type: string
                    minLength: 1
                    maxLength: 1250
                    description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - comment
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - email_send
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    minLength: 1
                    maxLength: 255
                  body:
                    type: string
                    minLength: 1
                    maxLength: 100000
                    description: HTML body template.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                  email_field:
                    type: string
                    nullable: true
                    description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                  cc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal copy addresses.
                  bcc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal blind-copy addresses.
                  attachments:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^wf_at_
                        name:
                          type: string
                          minLength: 1
                          maxLength: 255
                      required:
                        - sid
                        - name
                      additionalProperties: false
                    maxItems: 5
                    description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                  reply_in_thread:
                    type: boolean
                    nullable: true
                  track_opens:
                    type: boolean
                    nullable: true
                  track_clicks:
                    type: boolean
                    nullable: true
                  unsubscribe_link:
                    type: boolean
                    nullable: true
                required:
                  - type
                  - subject
                  - body
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  for:
                    type: string
                    pattern: ^[1-9][0-9]*[mhd]$
                    description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                required:
                  - type
                  - for
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait_for_event
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  event:
                    type: string
                    enum:
                      - linkedin_connection_request_accepted
                      - email_opened
                      - email_link_clicked
                    description: Event observed via the activities ingest.
                  timeout:
                    type: object
                    properties:
                      after:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                      steps:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - after
                      - steps
                    additionalProperties: false
                    description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                required:
                  - type
                  - event
                  - timeout
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - condition
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption.
                        when:
                          type: object
                          additionalProperties: {}
                          description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - when
                        - steps
                      additionalProperties: false
                    minItems: 1
                    maxItems: 9
                    description: 1..9 branches, evaluated in order, first match wins.
                  else:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                required:
                  - type
                  - branches
                  - else
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ab_test
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption ("Variant A").
                        weight:
                          type: integer
                          minimum: 1
                          description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - weight
                        - steps
                      additionalProperties: false
                    minItems: 2
                    maxItems: 9
                    description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                required:
                  - type
                  - branches
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - end
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - api_call
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  method:
                    type: string
                    enum:
                      - GET
                      - POST
                      - PUT
                      - PATCH
                      - DELETE
                  url:
                    type: string
                    minLength: 1
                    maxLength: 2048
                    description: https-only (publish check); a template - variables may stand in the path and the query.
                  headers:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 1024
                  query:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 2048
                  body:
                    type: string
                    nullable: true
                    maxLength: 16000
                    description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                  provider_connection_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^in_cn_
                    description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                  timeout_secs:
                    type: integer
                    nullable: true
                    minimum: 1
                    maximum: 120
                  retry_on_error:
                    type: boolean
                    nullable: true
                  remove_empty_values:
                    type: boolean
                    nullable: true
                  output_key:
                    type: string
                    nullable: true
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                required:
                  - type
                  - method
                  - url
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ask_ai
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  prompt:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Same variable namespaces as message templates.
                  output_key:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                  preset_sid:
                    type: string
                    nullable: true
                    description: gtm-api preset for the AI call; null = team default.
                required:
                  - type
                  - prompt
                  - output_key
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - manual_task
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  title:
                    type: string
                    minLength: 1
                    maxLength: 255
                  instructions:
                    type: string
                    nullable: true
                    maxLength: 4000
                    description: Rendered into the human todo; the journey waits until the task is completed.
                required:
                  - type
                  - title
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - move_to_workflow
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  target_workflow_sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                  mode:
                    type: string
                    nullable: true
                    enum:
                      - from_start
                      - from_current
                    description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                required:
                  - type
                  - target_workflow_sid
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - add_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - remove_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - set_field
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  field_slug:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                  value:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - {}
                      - {}
                    description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                required:
                  - type
                  - field_slug
                  - value
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - change_sender
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  sender_profile_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                    description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                  rotation:
                    type: string
                    nullable: true
                    enum:
                      - fair
                      - random
                      - new_sender
                      - prior_engagement
                    description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                required:
                  - type
                additionalProperties: false
          description: FULL-REPLACE of the working copy. Carry ids of kept steps verbatim; omit ids on new steps (assigned from step_id_seq). Dropping the id of an unchanged step risks a possible_lost_identity warning.
        schedule:
          type: object
          nullable: true
          properties:
            timeblocks:
              type: array
              items:
                type: object
                properties:
                  dow:
                    type: integer
                    minimum: 0
                    maximum: 6
                    description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                  start_minute:
                    type: integer
                    minimum: 0
                    maximum: 1439
                    description: "Minutes from local midnight (legacy key: min)."
                  end_minute:
                    type: integer
                    minimum: 1
                    maximum: 1440
                    description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                required:
                  - dow
                  - start_minute
                  - end_minute
                additionalProperties: false
              minItems: 1
              maxItems: 7
              description: 1..7 blocks; at most one block per day-of-week in v1 (server-validated).
            timezone:
              type: string
              minLength: 1
              maxLength: 64
              description: IANA tz name, e.g. "Europe/Lisbon" - base timezone for the blocks.
            use_people_timezone:
              type: boolean
              description: Default false - resolve blocks in the person's timezone when known, fall back to `timezone` (legacy use_lead_timezone).
          required:
            - timeblocks
            - timezone
          additionalProperties: false
          description: Full-replace; null clears the windows (any time).
        on_reply:
          type: string
          enum:
            - autopilot
            - copilot
            - stop
            - continue
          description: Applies to the next replies and to the threads the workflow acts on from now on; a thread already stamped keeps its automation mode until the next report.
        agent_sid:
          type: string
          nullable: true
          minLength: 18
          maxLength: 18
          pattern: ^ub_ag_
          description: Pick the AI SDR for the threads this workflow starts (ub_ag_…); null = back to its table's pick. Reaches the open threads it started at their next turn.
        sender_profile_sids:
          type: array
          items:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_sp_
          description: Full-replace of the pool (existence-checked); already-pinned records keep their sender.
        rotation_strategy:
          type: string
          enum:
            - fair
            - random
            - new_sender
            - prior_engagement
          description: Applies to future enrollments only.
        priority:
          type: integer
          minimum: 1
          maximum: 3
          description: "New share of a shared sender profile: 1..3 (low / medium / high), never a rank."
        status:
          type: string
          enum:
            - archived
            - paused
            - draft
          description: "Archive family only: archived (from draft|paused); paused = unarchive (requires a published version); draft = unarchive (if never published). Transitions involving active → 422 invalid_transition (use pause/resume)."
    UpdateWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateWorkflowSourceRequest:
      type: object
      description: Request body of `update_workflow_source`.
      properties:
        event:
          type: string
          enum:
            - linkedin_connection_request_accepted
            - linkedin_message_replied
            - linkedin_inmail_replied
            - email_replied
            - email_opened
            - email_link_clicked
            - linkedin_invitation_received
            - linkedin_followed
            - website_visited
            - website_key_page_visited
            - website_form_submitted
          description: "type=event only: replace the enrolling activity type."
        name:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: New label; null clears it.
        auto_add:
          type: boolean
          description: Poller toggle. Turning it on enqueues an immediate sweep; true on a manual source → 422.
        view_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_vw_
          description: Repoint a type=view source at another live view (pt_vw_…). Sent on a non-view source → 422; cannot be nulled - a view source always points at a view.
        filter:
          anyOf:
            - type: object
              properties:
                and:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - and
              additionalProperties: false
            - type: object
              properties:
                or:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  minItems: 1
                  maxItems: 20
              required:
                - or
              additionalProperties: false
            - type: object
              properties:
                not:
                  type: object
                  additionalProperties: {}
                  description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
              required:
                - not
              additionalProperties: false
            - type: object
              properties:
                any:
                  type: object
                  properties:
                    path:
                      type: string
                      minLength: 1
                      description: Array-valued path - the only way to reach inside an array.
                    where:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - path
                    - where
                  additionalProperties: false
              required:
                - any
              additionalProperties: false
            - type: object
              properties:
                field:
                  type: string
                  minLength: 1
                  description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                op:
                  type: object
                  properties:
                    eq:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar equality. eq: null is rejected - use is_null."
                    ne:
                      anyOf:
                        - type: string
                        - type: number
                        - type: boolean
                      description: "Scalar inequality. ne: null is rejected - use is_null."
                    in:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value in list, 1..100 scalars.
                    nin:
                      type: array
                      items:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                      minItems: 1
                      maxItems: 100
                      description: Value not in list, 1..100 scalars.
                    gt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Greater than; string operand = ISO 8601 datetime.
                    gte:
                      anyOf:
                        - type: number
                        - type: string
                      description: ">= bound; pair with lte in the SAME op for a range."
                    lt:
                      anyOf:
                        - type: number
                        - type: string
                      description: Less than; string operand = ISO 8601 datetime.
                    lte:
                      anyOf:
                        - type: number
                        - type: string
                      description: <= bound; pair with gte in the SAME op for a range.
                    is_null:
                      type: boolean
                      description: true = absent-or-null; false = present and non-null.
                    contains:
                      type: string
                      minLength: 1
                      description: Case-insensitive substring match.
                    not_contains:
                      type: string
                      minLength: 1
                      description: Negated case-insensitive substring match.
                    contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when ANY is a ci substring.
                    not_contains_any:
                      type: array
                      items:
                        type: string
                        minLength: 1
                      minItems: 1
                      maxItems: 50
                      description: 1..50 strings; true when NONE is a ci substring.
                    starts_with:
                      type: string
                      minLength: 1
                      description: Case-insensitive prefix match.
                  additionalProperties: false
              required:
                - field
                - op
              additionalProperties: false
          description: Full replace of a type=filter source's AST (not a merge). Sent on a non-filter source → 422. The next cycle honors it; already-enrolled records untouched.
        active_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "Enrollment throttle: max simultaneous in-flight records from this source; null clears it (unlimited). Lowering below current in-flight evicts no one - new entries just wait."
        coworkers_limit:
          type: integer
          nullable: true
          minimum: 1
          description: "Enrollment throttle: max simultaneous in-flight records from this source per company; null clears it (unlimited)."
    UpdateWorkflowSourceResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Source sid (wf_sr_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              description: "[ro] Parent workflow (wf_wf_…) - see ./workflows.md."
            view_sid:
              type: string
              nullable: true
              description: Audience view (pt_vw_…) - set on type=view only, null otherwise; repointable via update - see ./playtable_views.md.
            name:
              type: string
              nullable: true
              description: Optional label ("Conference batch"), max 255; null = unlabeled.
            type:
              type: string
              enum:
                - view
                - filter
                - manual
                - event
              description: "[ro] view = playtable view membership | filter = inline AST | manual = hand-picked people. Immutable - repoint = delete + create."
            event:
              type: string
              nullable: true
              enum:
                - linkedin_connection_request_accepted
                - linkedin_message_replied
                - linkedin_inmail_replied
                - email_replied
                - email_opened
                - email_link_clicked
                - linkedin_invitation_received
                - linkedin_followed
                - website_visited
                - website_key_page_visited
                - website_form_submitted
              description: "type=event only: the activity type that enrolls a person (required at create for an event source, 422 otherwise); null on the other types."
            filter:
              anyOf:
                - type: object
                  properties:
                    and:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - and
                  additionalProperties: false
                - type: object
                  properties:
                    or:
                      type: array
                      items:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      minItems: 1
                      maxItems: 20
                  required:
                    - or
                  additionalProperties: false
                - type: object
                  properties:
                    not:
                      type: object
                      additionalProperties: {}
                      description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                  required:
                    - not
                  additionalProperties: false
                - type: object
                  properties:
                    any:
                      type: object
                      properties:
                        path:
                          type: string
                          minLength: 1
                          description: Array-valued path - the only way to reach inside an array.
                        where:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - path
                        - where
                      additionalProperties: false
                  required:
                    - any
                  additionalProperties: false
                - type: object
                  properties:
                    field:
                      type: string
                      minLength: 1
                      description: "Namespaced path: built-in people attribute or \"record.<slug>\" resolved per person's playtable (missing slug ⇒ leaf false); element-relative inside any.where."
                    op:
                      type: object
                      properties:
                        eq:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar equality. eq: null is rejected - use is_null."
                        ne:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: "Scalar inequality. ne: null is rejected - use is_null."
                        in:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value in list, 1..100 scalars.
                        nin:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                          minItems: 1
                          maxItems: 100
                          description: Value not in list, 1..100 scalars.
                        gt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Greater than; string operand = ISO 8601 datetime.
                        gte:
                          anyOf:
                            - type: number
                            - type: string
                          description: ">= bound; pair with lte in the SAME op for a range."
                        lt:
                          anyOf:
                            - type: number
                            - type: string
                          description: Less than; string operand = ISO 8601 datetime.
                        lte:
                          anyOf:
                            - type: number
                            - type: string
                          description: <= bound; pair with gte in the SAME op for a range.
                        is_null:
                          type: boolean
                          description: true = absent-or-null; false = present and non-null.
                        contains:
                          type: string
                          minLength: 1
                          description: Case-insensitive substring match.
                        not_contains:
                          type: string
                          minLength: 1
                          description: Negated case-insensitive substring match.
                        contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when ANY is a ci substring.
                        not_contains_any:
                          type: array
                          items:
                            type: string
                            minLength: 1
                          minItems: 1
                          maxItems: 50
                          description: 1..50 strings; true when NONE is a ci substring.
                        starts_with:
                          type: string
                          minLength: 1
                          description: Case-insensitive prefix match.
                      additionalProperties: false
                  required:
                    - field
                    - op
                  additionalProperties: false
                - {}
              description: Inline audience AST (type=filter only, null otherwise) over the team's people; ES resolves membership, record.<slug> leaves resolve per person's playtable (missing slug ⇒ false).
            auto_add:
              type: boolean
              description: "Poller toggle (view/filter): true = every cycle (~10 min) ES lists current audience members and MySQL decides entry; false = dormant pointer. Always false on manual."
            active_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight (non-terminal) records entered via THIS source; null = unlimited. Reached => new candidates wait (blocked_limit_count).
            coworkers_limit:
              type: integer
              nullable: true
              minimum: 1
              description: Max simultaneous in-flight records from THIS source for people of the SAME company; null = unlimited. Reached for a company => that company's candidates wait.
            entered_count:
              type: integer
              minimum: 0
              description: "[ro] Total workflow_records ever inserted via this source - monotonic on ALL types (cache of the entered_via_source_sid count)."
            blocked_stoplisted_count:
              type: integer
              minimum: 0
              description: "[ro] Stoplist entry blocks. view/filter: LIVE backlog gauge, recomputed each poll cycle over current audience members (un-stoplisted people drop out and enter); manual: cumulative per call."
            blocked_duplicate_in_workflow_count:
              type: integer
              minimum: 0
              description: "[ro] Poller-only: candidates skipped as already enrolled in this workflow via ANY source (auto_add never re-enters). view/filter: live gauge per poll cycle; ~0 on manual (add-people re-enters instead)."
            blocked_limit_count:
              type: integer
              minimum: 0
              description: "[ro] Candidates WAITING because active_limit / coworkers_limit is reached this cycle; they enter automatically once a slot frees. view/filter: live gauge; manual: cumulative per call."
            blocked_other_count:
              type: integer
              minimum: 0
              description: "[ro] Blocked as deleted/missing/otherwise ineligible people. view/filter: live gauge per poll cycle; manual: cumulative per call."
            last_evaluated_at:
              type: string
              nullable: true
              description: "[ro] Last poll cycle (view/filter) or last add-people / inline-create batch (manual); ISO 8601 UTC, null = never evaluated."
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that attached the feed (AccessIdentityValue).
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
              description: Actor that soft-deleted the feed (own verb or workflows.delete cascade); null while live.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC; null = live (soft delete - the poller gates on it).
          required:
            - sid
            - team_sid
            - workflow_sid
            - view_sid
            - name
            - type
            - filter
            - auto_add
            - active_limit
            - coworkers_limit
            - entered_count
            - blocked_stoplisted_count
            - blocked_duplicate_in_workflow_count
            - blocked_limit_count
            - blocked_other_count
            - last_evaluated_at
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    UpdateWorkflowTaskRequest:
      type: object
      description: Request body of `update_workflow_task`.
      properties:
        variables_snapshot:
          type: object
          additionalProperties:
            type: string
          description: "Partial: the rendered text fields to replace, keyed by the type's template field (message / subject / body / comment / prompt / title / instructions). Unknown keys and over-cap values → 422."
        scheduled_at:
          type: string
          format: date-time
          description: When the task may run (ISO 8601). A past time clamps to now = "send now".
    UpdateWorkflowTaskResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            workflow_sid:
              type: string
              nullable: true
              description: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
            workflow_version_sid:
              type: string
              nullable: true
              description: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
            workflow_record_sid:
              type: string
              nullable: true
              description: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
            people_sid:
              type: string
              description: The person (cr_pp_…), denormalized for the person timeline.
            step_id:
              type: integer
              nullable: true
              description: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
            type:
              type: string
              enum:
                - linkedin_send_connection_request
                - linkedin_send_message
                - linkedin_send_inmail
                - linkedin_visit_profile
                - linkedin_endorse_skills
                - linkedin_withdraw_connection_request
                - email_send
                - wait
                - wait_for_event
                - condition
                - api_call
                - ask_ai
                - manual_task
                - linkedin_like_latest_post
                - linkedin_comment_latest_post
                - ab_test
                - move_to_workflow
                - add_tag
                - remove_tag
                - set_field
                - change_sender
                - run_column
              description: "Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values."
            attempt:
              type: integer
              description: "Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept."
            status:
              type: string
              enum:
                - pending
                - scheduled
                - dispatched
                - done
                - failed
                - skipped
                - skipped_reply
                - skipped_stoplisted
                - cancelled
                - expired
              description: "Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on."
            initiator:
              type: string
              enum:
                - workflow_record
                - play
                - user
              description: "workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message."
            play_sid:
              type: string
              nullable: true
              description: The play that bore the task (pt_pl_…); null on a journey's task.
            trigger_activity_sid:
              type: string
              nullable: true
              description: "The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null."
            act:
              type: object
              nullable: true
              properties:
                do:
                  type: string
                  enum:
                    - send_message
                    - add_to_workflow
                    - like
                    - comment
                    - ask
                  description: "What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options)."
                about:
                  type: string
                  enum:
                    - birthday
                    - work_anniversary
                    - job_change
                    - post
                    - website_visit
                    - event
                  description: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
                actor_sid:
                  type: string
                  description: "A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid."
                target_workflow_sid:
                  type: string
                  description: add_to_workflow, and a question whose move or add names one.
                post_urn:
                  type: string
                  description: "like, comment: the post the act goes to (an activity URN)."
                reaction:
                  type: string
                  description: "like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post."
                options:
                  type: array
                  items:
                    type: string
                    enum:
                      - remove
                      - keep
                      - move
                      - add
                  description: "ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey."
                suggested:
                  type: string
                  enum:
                    - remove
                    - keep
                    - move
                    - add
                  description: "ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask."
              required:
                - do
                - about
              description: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
            sender_profile_sid:
              type: string
              nullable: true
              description: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
            assignee_user_sid:
              type: string
              nullable: true
              description: "manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue."
            scheduled_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
            timeout_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge."
            dispatched_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped on scheduled → dispatched.
            expires_at:
              type: string
              nullable: true
              description: "ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h)."
            finished_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - stamped once on any terminal status.
            variables_snapshot:
              type: object
              nullable: true
              additionalProperties:
                type: string
              description: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
            result:
              type: object
              nullable: true
              additionalProperties: {}
              description: "Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do)."
            error_code:
              type: string
              nullable: true
              description: "Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task)."
            error_message:
              type: string
              nullable: true
              description: Human detail of the failure (max 1024); null on a skip.
            previous_attempts:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  attempt:
                    type: integer
                    description: The attempt number it was.
                  status:
                    type: string
                    enum:
                      - pending
                      - scheduled
                      - dispatched
                      - done
                      - failed
                      - skipped
                      - skipped_reply
                      - skipped_stoplisted
                      - cancelled
                      - expired
                    description: "How it ended: failed | expired | skipped_stoplisted (the retryable outcomes)."
                  error_code:
                    type: string
                    nullable: true
                    description: Its reason token.
                  error_message:
                    type: string
                    nullable: true
                  result:
                    type: object
                    nullable: true
                    additionalProperties: {}
                    description: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
                  dispatched_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                  finished_at:
                    type: string
                    nullable: true
                    description: ISO 8601 UTC.
                required:
                  - attempt
                  - status
                  - error_code
                  - error_message
                  - result
                  - dispatched_at
                  - finished_at
              description: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
            created_at:
              type: string
              description: ISO 8601 UTC - the planning moment.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
          required:
            - sid
            - team_sid
            - workflow_sid
            - workflow_version_sid
            - workflow_record_sid
            - people_sid
            - step_id
            - type
            - attempt
            - status
            - initiator
            - play_sid
            - trigger_activity_sid
            - act
            - sender_profile_sid
            - assignee_user_sid
            - scheduled_at
            - timeout_at
            - dispatched_at
            - expires_at
            - finished_at
            - variables_snapshot
            - result
            - error_code
            - error_message
            - previous_attempts
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    ValidateWorkflowRequest:
      type: object
      description: Request body of `validate_workflow`.
      properties:
        draft_steps:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    nullable: true
                    description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_message
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Message template (same namespaces as all templates).
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_send_inmail
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    nullable: true
                    maxLength: 200
                  message:
                    type: string
                    minLength: 1
                    maxLength: 8000
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - message
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_visit_profile
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_endorse_skills
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  skills_count:
                    type: integer
                    minimum: 1
                    maximum: 10
                    description: Endorse the person's top N listed skills, 1..10.
                required:
                  - type
                  - skills_count
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_withdraw_connection_request
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_like_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - linkedin_comment_latest_post
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  comment:
                    type: string
                    minLength: 1
                    maxLength: 1250
                    description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                required:
                  - type
                  - comment
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - email_send
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  subject:
                    type: string
                    minLength: 1
                    maxLength: 255
                  body:
                    type: string
                    minLength: 1
                    maxLength: 100000
                    description: HTML body template.
                  required_fields:
                    type: object
                    nullable: true
                    properties:
                      refs:
                        type: array
                        items:
                          type: string
                          maxLength: 160
                          pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                        maxItems: 20
                        description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                      on_missing:
                        type: string
                        enum:
                          - fail
                          - skip
                        description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                    required:
                      - refs
                      - on_missing
                    additionalProperties: false
                  email_field:
                    type: string
                    nullable: true
                    description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                  cc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal copy addresses.
                  bcc:
                    type: array
                    nullable: true
                    items:
                      type: string
                      maxLength: 320
                      format: email
                    maxItems: 5
                    description: Up to 5 literal blind-copy addresses.
                  attachments:
                    type: array
                    nullable: true
                    items:
                      type: object
                      properties:
                        sid:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^wf_at_
                        name:
                          type: string
                          minLength: 1
                          maxLength: 255
                      required:
                        - sid
                        - name
                      additionalProperties: false
                    maxItems: 5
                    description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                  reply_in_thread:
                    type: boolean
                    nullable: true
                  track_opens:
                    type: boolean
                    nullable: true
                  track_clicks:
                    type: boolean
                    nullable: true
                  unsubscribe_link:
                    type: boolean
                    nullable: true
                required:
                  - type
                  - subject
                  - body
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  for:
                    type: string
                    pattern: ^[1-9][0-9]*[mhd]$
                    description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                required:
                  - type
                  - for
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - wait_for_event
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  event:
                    type: string
                    enum:
                      - linkedin_connection_request_accepted
                      - email_opened
                      - email_link_clicked
                    description: Event observed via the activities ingest.
                  timeout:
                    type: object
                    properties:
                      after:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                      steps:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - after
                      - steps
                    additionalProperties: false
                    description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                required:
                  - type
                  - event
                  - timeout
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - condition
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption.
                        when:
                          type: object
                          additionalProperties: {}
                          description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - when
                        - steps
                      additionalProperties: false
                    minItems: 1
                    maxItems: 9
                    description: 1..9 branches, evaluated in order, first match wins.
                  else:
                    type: object
                    additionalProperties: {}
                    description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                required:
                  - type
                  - branches
                  - else
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ab_test
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  branches:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          minimum: 1
                          description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                        label:
                          type: string
                          nullable: true
                          maxLength: 255
                          description: Editor caption ("Variant A").
                        weight:
                          type: integer
                          minimum: 1
                          description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                        steps:
                          type: object
                          additionalProperties: {}
                          description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                      required:
                        - weight
                        - steps
                      additionalProperties: false
                    minItems: 2
                    maxItems: 9
                    description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                required:
                  - type
                  - branches
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - end
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                required:
                  - type
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - api_call
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  method:
                    type: string
                    enum:
                      - GET
                      - POST
                      - PUT
                      - PATCH
                      - DELETE
                  url:
                    type: string
                    minLength: 1
                    maxLength: 2048
                    description: https-only (publish check); a template - variables may stand in the path and the query.
                  headers:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 1024
                  query:
                    type: object
                    nullable: true
                    additionalProperties:
                      type: string
                      maxLength: 2048
                  body:
                    type: string
                    nullable: true
                    maxLength: 16000
                    description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                  provider_connection_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^in_cn_
                    description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                  timeout_secs:
                    type: integer
                    nullable: true
                    minimum: 1
                    maximum: 120
                  retry_on_error:
                    type: boolean
                    nullable: true
                  remove_empty_values:
                    type: boolean
                    nullable: true
                  output_key:
                    type: string
                    nullable: true
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                required:
                  - type
                  - method
                  - url
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - ask_ai
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  prompt:
                    type: string
                    minLength: 1
                    maxLength: 8000
                    description: Same variable namespaces as message templates.
                  output_key:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                  preset_sid:
                    type: string
                    nullable: true
                    description: gtm-api preset for the AI call; null = team default.
                required:
                  - type
                  - prompt
                  - output_key
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - manual_task
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  title:
                    type: string
                    minLength: 1
                    maxLength: 255
                  instructions:
                    type: string
                    nullable: true
                    maxLength: 4000
                    description: Rendered into the human todo; the journey waits until the task is completed.
                required:
                  - type
                  - title
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - move_to_workflow
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  target_workflow_sid:
                    type: string
                    minLength: 18
                    maxLength: 18
                    pattern: ^wf_wf_
                    description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                  mode:
                    type: string
                    nullable: true
                    enum:
                      - from_start
                      - from_current
                    description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                required:
                  - type
                  - target_workflow_sid
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - add_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - remove_tag
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  tag_sids:
                    type: array
                    items:
                      type: string
                      minLength: 18
                      maxLength: 18
                      pattern: ^cr_tg_
                    minItems: 1
                    maxItems: 20
                    description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                required:
                  - type
                  - tag_sids
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - set_field
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  field_slug:
                    type: string
                    pattern: ^[a-z][a-z0-9_]{0,63}$
                    description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                  value:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - {}
                      - {}
                    description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                required:
                  - type
                  - field_slug
                  - value
                additionalProperties: false
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                      - change_sender
                  id:
                    type: integer
                    minimum: 1
                    description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                  name:
                    type: string
                    nullable: true
                    maxLength: 255
                    description: Editor label.
                  sender_profile_sid:
                    type: string
                    nullable: true
                    minLength: 18
                    maxLength: 18
                    pattern: ^ub_sp_
                    description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                  rotation:
                    type: string
                    nullable: true
                    enum:
                      - fair
                      - random
                      - new_sender
                      - prior_engagement
                    description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                required:
                  - type
                additionalProperties: false
          description: "Stateless mode: validate this document before/without saving. New-step ids optional; no id assignment happens."
        sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^wf_wf_
          description: "Sid mode: validate the SAVED draft of this workflow in place."
    ValidateWorkflowResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item:
          type: object
          nullable: true
          properties:
            sid:
              type: string
            team_sid:
              type: string
            name:
              type: string
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - draft
                - active
                - paused
                - archived
            published_version_sid:
              type: string
              nullable: true
              description: wf_vr_… [ro] - written ONLY by publish; null until first publish. Old versions are never repointed back to (no rollback verb - republish the old steps instead).
            draft_steps:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        nullable: true
                        description: "Invite note - max 300 RENDERED chars (server-checked); null/omitted = blank invite. Template namespaces: {{people.*}} {{company.*}} {{record.<slug>}} {{ai.<key>}}; per-variable fallback {{record.slug|text}}."
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_message
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Message template (same namespaces as all templates).
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_send_inmail
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        nullable: true
                        maxLength: 200
                      message:
                        type: string
                        minLength: 1
                        maxLength: 8000
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - message
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_visit_profile
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_endorse_skills
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      skills_count:
                        type: integer
                        minimum: 1
                        maximum: 10
                        description: Endorse the person's top N listed skills, 1..10.
                    required:
                      - type
                      - skills_count
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_withdraw_connection_request
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_like_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - linkedin_comment_latest_post
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      comment:
                        type: string
                        minLength: 1
                        maxLength: 1250
                        description: Comment template on the person's latest post, 1..1250 rendered; same namespaces as message templates.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                    required:
                      - type
                      - comment
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - email_send
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      subject:
                        type: string
                        minLength: 1
                        maxLength: 255
                      body:
                        type: string
                        minLength: 1
                        maxLength: 100000
                        description: HTML body template.
                      required_fields:
                        type: object
                        nullable: true
                        properties:
                          refs:
                            type: array
                            items:
                              type: string
                              maxLength: 160
                              pattern: ^(people|company|record|ai|api)\.[a-z][a-z0-9_]*(\.[a-z0-9_]+)*$
                            maxItems: 20
                            description: 0..20 bare template refs required on top of the text's own variables (people.first_name, company.name, record.<slug>, company.record.<slug>, ai.<key>).
                          on_missing:
                            type: string
                            enum:
                              - fail
                              - skip
                            description: fail | skip - what to do when a value the text needs is empty at task time; no policy (null) sends the text as it renders.
                        required:
                          - refs
                          - on_missing
                        additionalProperties: false
                      email_field:
                        type: string
                        nullable: true
                        description: "Which address the send uses: any | work_email | personal_email; omitted or any = the best one."
                      cc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal copy addresses.
                      bcc:
                        type: array
                        nullable: true
                        items:
                          type: string
                          maxLength: 320
                          format: email
                        maxItems: 5
                        description: Up to 5 literal blind-copy addresses.
                      attachments:
                        type: array
                        nullable: true
                        items:
                          type: object
                          properties:
                            sid:
                              type: string
                              minLength: 18
                              maxLength: 18
                              pattern: ^wf_at_
                            name:
                              type: string
                              minLength: 1
                              maxLength: 255
                          required:
                            - sid
                            - name
                          additionalProperties: false
                        maxItems: 5
                        description: "Up to 5 library files ({sid: wf_at_…, name}) sent with the email."
                      reply_in_thread:
                        type: boolean
                        nullable: true
                      track_opens:
                        type: boolean
                        nullable: true
                      track_clicks:
                        type: boolean
                        nullable: true
                      unsubscribe_link:
                        type: boolean
                        nullable: true
                    required:
                      - type
                      - subject
                      - body
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      for:
                        type: string
                        pattern: ^[1-9][0-9]*[mhd]$
                        description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                    required:
                      - type
                      - for
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - wait_for_event
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      event:
                        type: string
                        enum:
                          - linkedin_connection_request_accepted
                          - email_opened
                          - email_link_clicked
                        description: Event observed via the activities ingest.
                      timeout:
                        type: object
                        properties:
                          after:
                            type: string
                            pattern: ^[1-9][0-9]*[mhd]$
                            description: 'Duration string: ^[1-9][0-9]*(m|h|d)$ - e.g. "45m", "12h", "14d". Publish lints the range 1m..365d.'
                          steps:
                            type: object
                            additionalProperties: {}
                            description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                        required:
                          - after
                          - steps
                        additionalProperties: false
                        description: "Required since 2026-10-11: a wait always has a time limit. Bundled: a timeout path cannot exist without a duration."
                    required:
                      - type
                      - event
                      - timeout
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - condition
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new branches, carry on kept ones. The fired branch id lands on the condition task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption.
                            when:
                              type: object
                              additionalProperties: {}
                              description: "NON-nullable filter AST, LOOSE mode (predicate-only, never compiled to ES): leaf paths people.* / company.* / record.<slug> / ai.<output_key> / api.<output_key>.<path>; a path missing from the record's playtable makes the leaf false."
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - when
                            - steps
                          additionalProperties: false
                        minItems: 1
                        maxItems: 9
                        description: 1..9 branches, evaluated in order, first match wins.
                      else:
                        type: object
                        additionalProperties: {}
                        description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                    required:
                      - type
                      - branches
                      - else
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ab_test
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      branches:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                              minimum: 1
                              description: Server-assigned - SAME id-space as step ids; omit on new arms, carry on kept ones. The assigned arm id lands on the ab_test task result.
                            label:
                              type: string
                              nullable: true
                              maxLength: 255
                              description: Editor caption ("Variant A").
                            weight:
                              type: integer
                              minimum: 1
                              description: Relative weight (int >= 1; need not sum to 100). Record assigned by crc32(record.sid) mod sum(weights) - see workflow_versions.md ab_test algorithm.
                            steps:
                              type: object
                              additionalProperties: {}
                              description: "Recursive node: the same object shape repeats here. A static OpenAPI document cannot express the cycle, so this level is documented as an open object."
                          required:
                            - weight
                            - steps
                          additionalProperties: false
                        minItems: 2
                        maxItems: 9
                        description: 2..9 weighted arms; the record is assigned deterministically by hashing its sid into the weight distribution. No `else`.
                    required:
                      - type
                      - branches
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - end
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                    required:
                      - type
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - api_call
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      method:
                        type: string
                        enum:
                          - GET
                          - POST
                          - PUT
                          - PATCH
                          - DELETE
                      url:
                        type: string
                        minLength: 1
                        maxLength: 2048
                        description: https-only (publish check); a template - variables may stand in the path and the query.
                      headers:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 1024
                      query:
                        type: object
                        nullable: true
                        additionalProperties:
                          type: string
                          maxLength: 2048
                      body:
                        type: string
                        nullable: true
                        maxLength: 16000
                        description: JSON body template, variables inside quotes; null = the fixed payload; must be null on GET / DELETE.
                      provider_connection_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^in_cn_
                        description: A `custom` provider connection whose auth the integration platform injects at call time; null = no auth.
                      timeout_secs:
                        type: integer
                        nullable: true
                        minimum: 1
                        maximum: 120
                      retry_on_error:
                        type: boolean
                        nullable: true
                      remove_empty_values:
                        type: boolean
                        nullable: true
                      output_key:
                        type: string
                        nullable: true
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: "The answer's name for later steps (2026-10-11): a slug, unique within the version with the ask_ai keys; later steps read {{api.<output_key>.<path>}} and condition leaves filter on api.<output_key>.<path>; null = the answer is not kept."
                    required:
                      - type
                      - method
                      - url
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - ask_ai
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      prompt:
                        type: string
                        minLength: 1
                        maxLength: 8000
                        description: Same variable namespaces as message templates.
                      output_key:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Slug, unique within the version (publish check) - later steps read {{ai.<output_key>}} / condition leaves on ai.<output_key>.
                      preset_sid:
                        type: string
                        nullable: true
                        description: gtm-api preset for the AI call; null = team default.
                    required:
                      - type
                      - prompt
                      - output_key
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - manual_task
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      title:
                        type: string
                        minLength: 1
                        maxLength: 255
                      instructions:
                        type: string
                        nullable: true
                        maxLength: 4000
                        description: Rendered into the human todo; the journey waits until the task is completed.
                    required:
                      - type
                      - title
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - move_to_workflow
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      target_workflow_sid:
                        type: string
                        minLength: 18
                        maxLength: 18
                        pattern: ^wf_wf_
                        description: Enroll the person into this campaign (wf_wf_…); reuses the existing record per the re-entry policy. THIS record then completes - terminal-for-this-record.
                      mode:
                        type: string
                        nullable: true
                        enum:
                          - from_start
                          - from_current
                        description: "Re-entry mode when the person is ALREADY in the target (workflow_records.md, Re-entry): from_start (default; reset to the entry step) | from_current (resume the pinned step, else the entry step). A re-entry is loop-guarded at re_entered_count 10."
                    required:
                      - type
                      - target_workflow_sid
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - add_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) attached to the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - remove_tag
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      tag_sids:
                        type: array
                        items:
                          type: string
                          minLength: 18
                          maxLength: 18
                          pattern: ^cr_tg_
                        minItems: 1
                        maxItems: 20
                        description: 1..20 CRM tags (cr_tg_…) detached from the person mid-flow, then falls through.
                    required:
                      - type
                      - tag_sids
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - set_field
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      field_slug:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,63}$
                        description: Playtable field slug to write (pipeline_stage is a scalar_select field).
                      value:
                        anyOf:
                          - type: string
                          - type: number
                          - type: boolean
                          - {}
                          - {}
                        description: Scalar cell value (one cell; no arrays/objects); null clears the field.
                    required:
                      - type
                      - field_slug
                      - value
                    additionalProperties: false
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - change_sender
                      id:
                        type: integer
                        minimum: 1
                        description: Server-assigned (workflows.step_id_seq). OMIT on new steps, CARRY verbatim on kept steps; always present on read.
                      name:
                        type: string
                        nullable: true
                        maxLength: 255
                        description: Editor label.
                      sender_profile_sid:
                        type: string
                        nullable: true
                        minLength: 18
                        maxLength: 18
                        pattern: ^ub_sp_
                        description: Explicit forward-only re-pin (ub_sp_…). Exactly one of sender_profile_sid / rotation (publish check). NOT a restart-from-top.
                      rotation:
                        type: string
                        nullable: true
                        enum:
                          - fair
                          - random
                          - new_sender
                          - prior_engagement
                        description: Re-pick the sender from the workflow pool by this strategy instead of a fixed sid. Exactly one of sender_profile_sid / rotation (publish check).
                    required:
                      - type
                    additionalProperties: false
              description: Working copy of the step document (chain-and-blocks v2); step ids always present on read (server-assigned). Not executable until published. Max 100 steps incl. nested / 512 KB.
            schedule:
              type: object
              nullable: true
              properties:
                timeblocks:
                  type: array
                  items:
                    type: object
                    properties:
                      dow:
                        type: integer
                        minimum: 0
                        maximum: 6
                        description: Day of week, 0=Sunday … 6=Saturday (legacy Carbon dayOfWeek convention).
                      start_minute:
                        type: integer
                        minimum: 0
                        maximum: 1439
                        description: "Minutes from local midnight (legacy key: min)."
                      end_minute:
                        type: integer
                        minimum: 1
                        maximum: 1440
                        description: "Minutes from local midnight; must be > start_minute (server-validated). Legacy key: max."
                    required:
                      - dow
                      - start_minute
                      - end_minute
                    additionalProperties: false
                timezone:
                  type: string
                  description: IANA tz name - base timezone for the blocks.
                use_people_timezone:
                  type: boolean
                  description: Resolve blocks in the person's timezone when known, falling back to `timezone`.
              required:
                - timeblocks
                - timezone
                - use_people_timezone
              description: "The campaign's sending windows, the one send-window gate: null = any time (gtm-api's per-account limits still pace the sends). A sender profile carries no window of its own (founder 2026-09-22)."
            on_reply:
              type: string
              enum:
                - autopilot
                - copilot
                - stop
                - continue
              description: "What a reply does (default copilot): autopilot = the records pause and the AI SDR answers within its caps; copilot = the records pause and the AI SDR drafts for approval; stop = the records pause and the thread is the human's; continue = the records keep sending (nurture), the agent stays out. Reply scope = all the person's live records. Frozen onto each thread the workflow acts on as its automation_ref mode (autopilot | copilot | off)."
            agent_sid:
              type: string
              nullable: true
              description: "The AI SDR picked for this workflow (ub_ag_…, block 10 step 10.2): the agent that works the threads it starts, every setting on the agent itself (update_agent). Null = its home table's pick, else the team's default. The campaign's own setup of before (ai_sdr_setup, 2026-10-12 to 2026-10-30) became an agent of its own in step 10.3."
            sender_profile_sids:
              type: array
              items:
                type: string
              description: ub_sp_… each - the sender pool; a record is pinned to ONE sender at enrollment by rotation_strategy.
            rotation_strategy:
              type: string
              enum:
                - fair
                - random
                - new_sender
                - prior_engagement
            priority:
              type: integer
              description: 1..3 (low / medium / high) - the workflow's SHARE of a sender profile it shares with other workflows (three actions of high for one of low), never a rank (see ./workflow_tasks.md).
            created_by:
              type: object
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            deleted_by:
              type: object
              nullable: true
              properties:
                actor_type:
                  type: string
                  enum:
                    - user
                    - support
                    - api_key
                    - system
                    - agent
                actor_sid:
                  type: string
                  nullable: true
                team_sid:
                  type: string
                actor_name:
                  type: string
                  nullable: true
                  description: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
                oauth_client_sid:
                  type: string
                  nullable: true
                  description: The acting OAuth client (id_oc_*); null off the OAuth path.
                reason:
                  type: string
                  nullable: true
                  description: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
                permissions:
                  type: object
                  additionalProperties: {}
                  description: "Internal audit context: the grant set the actor held at write time. Not a contract."
                cluster_id:
                  type: integer
                  nullable: true
                  description: "Internal audit context: the cluster that served the write."
                trace_id:
                  type: string
                  nullable: true
                  description: "Internal audit context: the trace id of the request that wrote the row."
              required:
                - actor_type
                - actor_sid
                - team_sid
                - permissions
            created_at:
              type: string
            updated_at:
              type: string
            deleted_at:
              type: string
              nullable: true
          required:
            - sid
            - team_sid
            - name
            - description
            - status
            - published_version_sid
            - draft_steps
            - schedule
            - on_reply
            - agent_sid
            - sender_profile_sids
            - rotation_strategy
            - priority
            - created_by
            - deleted_by
            - created_at
            - updated_at
            - deleted_at
        result:
          type: object
          properties:
            valid:
              type: boolean
              description: true = errors empty. Warnings alone never block publish.
            errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
              description: ALL errors at once (never fail-fast), keyed steps[id=N].{field} - array position steps[i] only for id-less new steps; each carries rule + received + fix hint (typo-distance hints on unknown variables).
            warnings:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
              description: Domain lints (e.g. two sends with no wait between them) - publish never blocks on these.
            preview:
              type: string
              description: Deterministic ASCII render of every execution path - ids, types, branch/timeout arms, end/completion markers. Relay it to the user instead of narrating the graph.
          required:
            - valid
            - errors
            - warnings
            - preview
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    WritePlaytableFieldValueRequest:
      type: object
      description: Request body of `write_playtable_field_value`.
      properties:
        playtable_field_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^pt_fd_
          description: "The column (pt_fd_…); the table and the object type derive from it. Unknown or another team's: 404."
        object_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^cr_(pp|co)_
          description: "The row: a person (cr_pp_…) or a company (cr_co_…) that belongs to the column's table (422 otherwise)."
        value:
          type: string
          nullable: true
          maxLength: 65535
          description: "The value to write, canonical string (max 65535). The key is required: null clears the cell, which stays done with value null, never empty."
      required:
        - playtable_field_sid
        - object_sid
        - value
    WritePlaytableFieldValueResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
            team_sid:
              type: string
            playtable_sid:
              type: string
            object_type:
              type: string
              enum:
                - people
                - company
            object_sid:
              type: string
            playtable_field_sid:
              type: string
            value:
              type: string
              nullable: true
            is_value_from_formula:
              type: boolean
            original_value:
              type: string
              nullable: true
              description: "The system-produced value the FIRST manual overwrite snapshotted, what reset restores; null unless is_overwritten. The list surface nulls it like meta: read it on get, update, write and reset."
            is_overwritten:
              type: boolean
              description: "The current value is a manual write over a system-produced one: the edited marker, and the one state reset accepts."
            is_not_valid:
              type: boolean
              description: A manually written value that could not be converted to the column's type (text in a number column), stored raw and flagged; system writers coerce or null instead.
            status:
              type: string
              enum:
                - empty
                - queued
                - running
                - done
                - error
                - run_condition_not_met
            cost:
              type: number
              nullable: true
            provider_sid:
              type: string
              nullable: true
            meta:
              type: object
              nullable: true
              properties:
                run_sid:
                  type: string
                  nullable: true
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      step_index:
                        type: number
                      tool_sid:
                        type: string
                      status:
                        type: string
                        enum:
                          - success
                          - failed
                          - skipped
                      cost:
                        type: number
                      error:
                        type: string
                        nullable: true
                      finished_at:
                        type: string
                        nullable: true
                      verdict:
                        type: string
                        nullable: true
                      email:
                        type: string
                        nullable: true
                    required:
                      - step_index
                      - tool_sid
                      - status
                      - cost
                      - error
                      - finished_at
              required:
                - run_sid
                - steps
            error_msg:
              type: string
              nullable: true
            finished_at:
              type: string
              nullable: true
            created_at:
              type: string
            updated_at:
              type: string
          required:
            - sid
            - team_sid
            - playtable_sid
            - object_type
            - object_sid
            - playtable_field_sid
            - value
            - is_value_from_formula
            - original_value
            - is_overwritten
            - is_not_valid
            - status
            - cost
            - provider_sid
            - meta
            - error_msg
            - finished_at
            - created_at
            - updated_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: The fields this write did not change because the person's own value stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
            actor_type:
              type: string
              nullable: true
              description: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
