openapi: 3.1.0
info:
  title: WALayer WhatsApp API
  version: "1.1.0"
  description: >
    The WALayer developer API. Link your own WhatsApp number and drive it over
    REST: send and read messages, manage groups, communities and channels,
    block contacts, publish stories, receive webhooks. Authenticate with an API
    key as a Bearer token: `Authorization: Bearer wsk_live_…`. Every response is
    wrapped in a `{ "data": … }` envelope; errors use
    `{ "error": { code, message, detail } }`.


    Scope: this API is WhatsApp actions ONLY. The account/platform surface — the
    CRM (contacts, tags, custom fields, segments), cross-tenant search, billing
    and usage — is NOT part of the developer API. Those are dashboard features
    reachable with a session cookie, and an API key is refused there with
    `403 FORBIDDEN` (`detail.surface = "dashboard"`).


    Many actions need a live WhatsApp socket. When no runner currently owns the
    session they answer `409 SESSION_NOT_CONNECTED` — the route is valid; connect
    the number first.
  license:
    name: Proprietary
servers:
  - url: https://api.walayer.dev
    description: Production
  - url: http://localhost:8080
    description: Local / self-hosted
security:
  - apiKey: []
tags:
  - name: Sessions
  - name: Pairing
  - name: Messages
  - name: Message actions
  - name: Contacts
  - name: Chats
  - name: Groups
  - name: Communities
  - name: Channels
  - name: Labels
  - name: Business
  - name: Media
  - name: Webhooks
  - name: Events
  - name: Suppressions

paths:
  /v1/sessions:
    get:
      tags: [Sessions]
      summary: "List linked numbers"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Sessions]
      summary: "Link a number"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CreateSession" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Sessions]
      summary: "Get a session"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Sessions]
      summary: "Update session settings"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Sessions]
      summary: "Delete a session (logout + shred)"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/logout:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Sessions]
      summary: "Log the number out"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/health:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Sessions]
      summary: "Trust score, warmup & delivery stats"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/settings:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Sessions]
      summary: "Get the settable session config"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/settings/reset:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Sessions]
      summary: "Reset session settings to plan defaults"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/limits:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Sessions]
      summary: "Current send caps & warmup limits"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/export:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Sessions]
      summary: "Export this session's data"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/proxy/rotate:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Sessions]
      summary: "Rotate the pinned egress proxy"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/pair:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Pairing]
      summary: "Start QR / phone-code pairing (SSE)"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/messages:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Messages]
      summary: "Send a message (17 types)"
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string }, description: "required — dedupe key (invariant I4)" }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/SendRequest" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/messages/bulk:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Messages]
      summary: "Send a warmup-gated campaign"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/BulkRequest" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/stories:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Messages]
      summary: "Publish a status / story"
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string }, description: "required — dedupe key (invariant I4)" }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages:
    get:
      tags: [Messages]
      summary: "List messages (filter, search, paginate)"
      parameters:
        - { name: status, in: query, required: false, schema: { type: string } }
        - { name: session, in: query, required: false, schema: { type: string } }
        - { name: direction, in: query, required: false, schema: { type: string } }
        - { name: q, in: query, required: false, schema: { type: string } }
        - { name: type, in: query, required: false, schema: { type: string } }
        - { name: from, in: query, required: false, schema: { type: string } }
        - { name: to, in: query, required: false, schema: { type: string } }
        - { name: limit, in: query, required: false, schema: { type: string } }
        - { name: cursor, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Messages]
      summary: "Get a message + status timeline"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/receipts:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Messages]
      summary: "Delivery / read receipts for a message"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/resend:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Messages]
      summary: "Resend an undelivered message"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/batches:
    get:
      tags: [Messages]
      summary: "List campaigns with progress"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/batches/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Messages]
      summary: "Campaign progress"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/star:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Message actions]
      summary: "Star / unstar a message"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/pin:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Message actions]
      summary: "Pin / unpin a message (24h/7d/30d)"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/read:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Message actions]
      summary: "Send a read receipt (inbound)"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/messages/{id}/played:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Message actions]
      summary: "Send a played receipt (voice note)"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/on-whatsapp:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Check numbers are on WhatsApp (≤50)"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/check:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Batch on-WhatsApp check (≤50)"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/resolve:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Resolve LID ↔ phone JID"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Chats]
      summary: "List conversations"
      parameters:
        - { name: q, in: query, required: false, schema: { type: string } }
        - { name: unread, in: query, required: false, schema: { type: string } }
        - { name: kind, in: query, required: false, schema: { type: string } }
        - { name: tag, in: query, required: false, schema: { type: string } }
        - { name: limit, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats/{jid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Chats]
      summary: "Get one chat with its state"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Chats]
      summary: "Delete a chat"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Chats]
      summary: "Pin / mute / unread / disappearing timer"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats/{jid}/messages:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Chats]
      summary: "Chat history"
      parameters:
        - { name: q, in: query, required: false, schema: { type: string } }
        - { name: limit, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats/{jid}/read:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Chats]
      summary: "Mark a chat read"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats/{jid}/archive:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Chats]
      summary: "Archive / unarchive a chat"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/chats/{jid}/presence:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Chats]
      summary: "Send typing / recording presence"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "List WhatsApp contacts"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    put:
      tags: [Contacts]
      summary: "Upsert a contact + labels"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/block:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Block a contact"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/unblock:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Unblock a contact"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/about:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "Contact 'about' text"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/profile:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "Contact profile"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/presence:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "Last observed presence"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/contacts/{jid}/presence/subscribe:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: jid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Subscribe to presence"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/blocklist:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "Recorded + live blocklist"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/profile:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Contacts]
      summary: "The linked number's own profile"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Contacts]
      summary: "Update push name / about"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/presence:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Contacts]
      summary: "Set own online / offline presence"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "List groups"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Groups]
      summary: "Create a group"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/joined:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Joined groups (live)"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/invite/accept:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Groups]
      summary: "Accept a group invite"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/invite/{code}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: code, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Group metadata by invite code"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Get group metadata"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Groups]
      summary: "Update subject / description"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/live:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Live group info"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/leave:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Groups]
      summary: "Leave a group"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/participants:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Groups]
      summary: "Add / remove / promote / demote"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/invite:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Get the invite link"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Groups]
      summary: "Revoke & return a new invite link"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/invite/send:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Groups]
      summary: "Send the invite link as a message"
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string }, description: "required — dedupe key (invariant I4)" }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/icon:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "Get the group icon"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    put:
      tags: [Groups]
      summary: "Set the group icon (JPEG media id)"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Groups]
      summary: "Delete the group icon"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/settings:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    patch:
      tags: [Groups]
      summary: "Announce / locked / approval / member-add"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/groups/{gid}/requests:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Groups]
      summary: "List join requests"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Groups]
      summary: "Approve / reject join requests"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Communities]
      summary: "List communities"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Communities]
      summary: "Create a community"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Communities]
      summary: "Get a community"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Communities]
      summary: "Update name / description"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Communities]
      summary: "Deactivate a community"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/subgroups:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Communities]
      summary: "List subgroups"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Communities]
      summary: "Link a group"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/subgroups/{gid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    delete:
      tags: [Communities]
      summary: "Unlink a group"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/subgroups/{gid}/join:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
      - { name: gid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Communities]
      summary: "Join a community subgroup"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/groups:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Communities]
      summary: "Create a group in the community"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/participants:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Communities]
      summary: "List participants"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Communities]
      summary: "Add / remove / promote / demote"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/communities/{cid}/invite:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    delete:
      tags: [Communities]
      summary: "Revoke the community invite"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Channels]
      summary: "List followed channels"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Channels]
      summary: "Create a newsletter"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/invite/{code}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: code, in: path, required: true, schema: { type: string } }
    get:
      tags: [Channels]
      summary: "Channel info by invite code"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/invite/{code}/subscribe:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: code, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Follow via invite code"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Channels]
      summary: "Get channel metadata"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    patch:
      tags: [Channels]
      summary: "Mute / unmute a channel"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Channels]
      summary: "Unfollow a channel"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/subscribe:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Follow a channel"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/unsubscribe:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Unfollow a channel"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/messages:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Channels]
      summary: "Channel message history"
      parameters:
        - { name: limit, in: query, required: false, schema: { type: string } }
        - { name: before, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Channels]
      summary: "Post to the channel"
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string }, description: "required — dedupe key (invariant I4)" }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/SendRequest" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/updates:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Channels]
      summary: "Reaction / view-count updates"
      parameters:
        - { name: limit, in: query, required: false, schema: { type: string } }
        - { name: since, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/track:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Subscribe to live updates"
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/messages/{msid}/react:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
      - { name: msid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "React to a channel message"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/messages/{msid}/view:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
      - { name: msid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Mark a channel message viewed"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/channels/{cid}/invite/send:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Channels]
      summary: "Send the channel invite as a message"
      parameters:
        - { name: Idempotency-Key, in: header, required: true, schema: { type: string }, description: "required — dedupe key (invariant I4)" }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/labels:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Labels]
      summary: "List WhatsApp labels"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Labels]
      summary: "Create a label"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/labels/{lid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: lid, in: path, required: true, schema: { type: string } }
    patch:
      tags: [Labels]
      summary: "Rename / recolour a label"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Labels]
      summary: "Delete a label"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/labels/{lid}/associations:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: lid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Labels]
      summary: "List label associations"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Labels]
      summary: "Label a chat or message"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Labels]
      summary: "Remove a label association"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/business/profile:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Business]
      summary: "Get a business profile"
      parameters:
        - { name: jid, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/business/orders/{oid}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: oid, in: path, required: true, schema: { type: string } }
    get:
      tags: [Business]
      summary: "Get order items"
      parameters:
        - { name: token, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/business/link/{code}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: code, in: path, required: true, schema: { type: string } }
    get:
      tags: [Business]
      summary: "Resolve a wa.me business link"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/calls/{cid}/reject:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
      - { name: cid, in: path, required: true, schema: { type: string } }
    post:
      tags: [Business]
      summary: "Reject an incoming call"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "202":
          description: Accepted (queued)
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/sessions/{id}/bots:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Business]
      summary: "List Meta AI bots"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/media:
    post:
      tags: [Media]
      summary: "Upload media for sending"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    get:
      tags: [Media]
      summary: "List the media library"
      parameters:
        - { name: session, in: query, required: false, schema: { type: string } }
        - { name: direction, in: query, required: false, schema: { type: string } }
        - { name: limit, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/media/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Media]
      summary: "Get media metadata + signed URL"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Media]
      summary: "Delete media"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/webhooks:
    get:
      tags: [Webhooks]
      summary: "List webhooks"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Webhooks]
      summary: "Create a webhook"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/webhooks/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    patch:
      tags: [Webhooks]
      summary: "Update a webhook"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    delete:
      tags: [Webhooks]
      summary: "Delete a webhook"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/webhooks/{id}/test:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Webhooks]
      summary: "Fire a signed test delivery"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/events:
    get:
      tags: [Events]
      summary: "Event history"
      parameters:
        - { name: since, in: query, required: false, schema: { type: string } }
        - { name: limit, in: query, required: false, schema: { type: string } }
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/events/types:
    get:
      tags: [Events]
      summary: "The event catalogue"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/events/{id}/redeliver:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Events]
      summary: "Redeliver an event"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/suppressions:
    get:
      tags: [Suppressions]
      summary: "List opt-outs"
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/RunnerGated" }
    post:
      tags: [Suppressions]
      summary: "Add an opt-out"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenericBody" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { $ref: "#/components/schemas/GenericEnvelope" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "409": { $ref: "#/components/responses/RunnerGated" }
  /v1/suppressions/{phone}:
    parameters:
      - { name: phone, in: path, required: true, schema: { type: string } }
    delete:
      tags: [Suppressions]
      summary: "Remove an opt-out"
      responses:
        "204":
          description: No content
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "422": { $ref: "#/components/responses/Validation" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/RunnerGated" }

components:
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: "API key as a Bearer token, e.g. `Authorization: Bearer wsk_live_…`"
  responses:
    Unauthorized:
      description: Missing or invalid credentials
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    Forbidden:
      description: "Refused — e.g. a dashboard-only (CRM/billing) route reached with an API key, or a missing scope"
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    NotFound:
      description: Not found
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    Validation:
      description: Request validation failed
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    RunnerGated:
      description: "The session has no live WhatsApp socket (SESSION_NOT_CONNECTED), or an idempotent conflict"
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code: { type: string, example: SESSION_NOT_CONNECTED }
            message: { type: string }
            detail: { type: object, additionalProperties: true }
    GenericBody:
      type: object
      additionalProperties: true
    GenericEnvelope:
      type: object
      properties: { data: { description: "endpoint-specific payload" } }
    Session:
      type: object
      properties:
        id: { type: string, example: sess_a1b2 }
        label: { type: string, nullable: true }
        country: { type: string, example: LK }
        status: { type: string, example: connected }
        warmup_stage: { type: integer }
    SessionEnvelope:
      type: object
      properties: { data: { $ref: "#/components/schemas/Session" } }
    CreateSession:
      type: object
      required: [country]
      properties:
        country: { type: string, minLength: 2, maxLength: 2, example: LK }
        label: { type: string }
        phone_number: { type: string }
    SendRequest:
      type: object
      required: [type, to, body]
      properties:
        type:
          type: string
          example: text
          description: >
            One of: text, image, video, audio, document, sticker, location,
            contact, reaction, poll, buttons, list, reply, forward, revoke, edit,
            presence, ptv, gif, link_preview, live_location, contact_list.
        to: { type: string, example: "+94770000000" }
        body: { type: object, additionalProperties: true, example: { text: "Hello 👋" } }
        options:
          type: object
          properties:
            quoted_message_id: { type: string }
            schedule_at: { type: integer, description: unix seconds }
            story: { type: object, additionalProperties: true }
    BulkRequest:
      type: object
      required: [name, template, recipients]
      properties:
        name: { type: string }
        template:
          type: object
          properties:
            type: { type: string }
            body: { type: object, additionalProperties: true }
        recipients:
          type: array
          items:
            type: object
            properties:
              to: { type: string }
              vars: { type: object, additionalProperties: { type: string } }
        schedule_at: { type: integer }
