openapi: 3.0.3
info:
  title: naturali.ai — Channel Kinds API
  version: 1.0.0
  description: >
    The surfaces and predicates each connectable channel kind publishes
    (design: CHANNELS-ROUTING.md §3.4/§3.5) — what a route's `surface` and
    `match` can name, read straight off the adapter and predicate registries
    so a console can render a route's condition builder without hardcoding
    either vocabulary.
  contact:
    name: naturali.ai
    url: https://naturali.ai
servers:
  - url: '{baseUrl}'
    description: Host of your naturali.ai deployment; every path carries the /v1 prefix.
    variables:
      baseUrl:
        description: Base host URL.
        default: https://api.naturali.ai
tags:
  - name: Channels
    description: Connect and manage a project's messaging surfaces (WhatsApp, Discord).
security:
  - bearerAuth: []
paths:
  /v1/channel-kinds:
    get:
      tags: [Channels]
      summary: List channel kinds
      description: >
        Every connectable kind, its surfaces, and the predicates its routes
        can match on (engine-wide ones like `address_known` plus its own,
        like Discord's `guild_id`).
      operationId: listChannelKinds
      responses:
        '200':
          description: Every channel kind.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChannelKindList'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: A naturali API key (nat_sk_…) or a session JWT.
  responses:
    Unauthorized:
      description: Missing or invalid credentials.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              example: unauthorized
            message:
              type: string
              example: Missing or invalid credentials.
            details:
              type: object
              additionalProperties: true
    ChannelSurface:
      type: object
      properties:
        name:
          type: string
          description: Stable, wire-visible id, unique within the kind.
          example: guild_thread
        title:
          type: string
          example: Server thread
        shared:
          type: boolean
          description: Several humans share one conversation here (a thread, a Slack channel).
          example: true
      required: [name, title, shared]
    ChannelPredicate:
      type: object
      properties:
        name:
          type: string
          example: guild_id
        type:
          type: string
          description: The value shape this predicate's `match` entry expects.
          example: string
      required: [name, type]
    ChannelKind:
      type: object
      properties:
        kind:
          type: string
          enum: [whatsapp, discord]
          example: discord
        surfaces:
          type: array
          items:
            $ref: '#/components/schemas/ChannelSurface'
        predicates:
          type: array
          items:
            $ref: '#/components/schemas/ChannelPredicate'
      required: [kind, surfaces, predicates]
    ChannelKindList:
      type: object
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ChannelKind'
