openapi: 3.1.0
info:
  title: Bow Chat Integration API
  version: 1.0.0
  summary: Send and observe customer messages through a Bow Chat workspace.
  description: |
    This supported subset covers the normal integration path: discover an inbox,
    resolve a contact, create or reuse a conversation, send a message, read its
    status, and subscribe to message webhooks. Channel rules still apply. In
    particular, WhatsApp Business Platform templates must be approved by Meta,
    and a WhatsApp Web connection does not create a bulk-messaging entitlement.
servers:
  - url: https://app.bow.chat
security:
  - UserApiKey: []
tags:
  - name: Inboxes
  - name: Contacts
  - name: Conversations
  - name: Messages
  - name: Webhooks
paths:
  /api/v1/accounts/{account_id}/inboxes:
    get:
      tags: [Inboxes]
      operationId: listInboxes
      summary: List the workspace inboxes
      parameters:
        - $ref: '#/components/parameters/AccountId'
      responses:
        '200':
          description: Inbox list
          content:
            application/json:
              schema:
                type: object
                properties:
                  payload:
                    type: array
                    items:
                      $ref: '#/components/schemas/Inbox'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v1/accounts/{account_id}/contacts/search:
    get:
      tags: [Contacts]
      operationId: searchContacts
      summary: Find an existing contact
      description: Search by name, external identifier, email, or phone number. Results are paginated.
      parameters:
        - $ref: '#/components/parameters/AccountId'
        - name: q
          in: query
          required: true
          schema:
            type: string
          example: '+40722123456'
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
      responses:
        '200':
          description: Matching contacts
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/accounts/{account_id}/contacts:
    post:
      tags: [Contacts]
      operationId: createContact
      summary: Create a contact in an inbox
      parameters:
        - $ref: '#/components/parameters/AccountId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateContact'
            example:
              inbox_id: 14001
              name: Ana Popescu
              phone_number: '+40722123456'
              identifier: setrio-patient-84291
              additional_attributes:
                source: setrio
      responses:
        '200':
          description: Contact and inbox identity created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/accounts/{account_id}/contacts/{contact_id}/contactable_inboxes:
    get:
      tags: [Contacts]
      operationId: listContactableInboxes
      summary: Get the source identity to use for a contact and inbox
      parameters:
        - $ref: '#/components/parameters/AccountId'
        - $ref: '#/components/parameters/ContactId'
      responses:
        '200':
          description: Contactable inboxes and source IDs
          content:
            application/json:
              schema:
                type: object
                properties:
                  payload:
                    type: array
                    items:
                      type: object
                      properties:
                        source_id:
                          type: string
                        inbox:
                          $ref: '#/components/schemas/Inbox'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/BadRequest'
  /api/v1/accounts/{account_id}/conversations:
    get:
      tags: [Conversations]
      operationId: listConversations
      summary: List conversations
      parameters:
        - $ref: '#/components/parameters/AccountId'
        - name: inbox_id
          in: query
          schema:
            type: integer
        - name: status
          in: query
          schema:
            type: string
            enum: [all, open, resolved, pending, snoozed]
            default: open
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
      responses:
        '200':
          description: Paginated conversations
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags: [Conversations]
      operationId: createConversation
      summary: Start a conversation for a contact
      description: Store the returned display ID and reuse it for later message calls.
      parameters:
        - $ref: '#/components/parameters/AccountId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateConversation'
            example:
              source_id: '40722123456'
              inbox_id: 14001
              contact_id: 84291
              status: open
      responses:
        '200':
          description: Conversation created or resolved by the provider-specific identity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Conversation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages:
    get:
      tags: [Messages]
      operationId: listMessages
      summary: Read messages and current delivery state
      parameters:
        - $ref: '#/components/parameters/AccountId'
        - $ref: '#/components/parameters/ConversationId'
      responses:
        '200':
          description: Conversation messages
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    type: object
                    additionalProperties: true
                  payload:
                    type: array
                    items:
                      $ref: '#/components/schemas/Message'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      tags: [Messages]
      operationId: createMessage
      summary: Send an outgoing message
      description: |
        Use template_params for an approved WhatsApp Business Platform template.
        A successful HTTP response means Bow Chat accepted the request; use
        message_updated webhooks or this message list to observe delivered,
        read, or failed status.
      parameters:
        - $ref: '#/components/parameters/AccountId'
        - $ref: '#/components/parameters/ConversationId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMessage'
            examples:
              freeForm:
                summary: Free-form message where the channel permits it
                value:
                  content: Your appointment is confirmed for 14:30.
                  message_type: outgoing
                  private: false
              utilityTemplate:
                summary: Approved utility template
                value:
                  content: Your appointment is confirmed for 14:30.
                  message_type: outgoing
                  private: false
                  template_params:
                    name: appointment_confirmation
                    category: UTILITY
                    language: ro
                    processed_params:
                      body:
                        '1': '14:30'
      responses:
        '200':
          description: Message accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/v1/accounts/{account_id}/webhooks:
    get:
      tags: [Webhooks]
      operationId: listWebhooks
      summary: List account webhooks
      parameters:
        - $ref: '#/components/parameters/AccountId'
      responses:
        '200':
          description: Webhook list
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags: [Webhooks]
      operationId: createWebhook
      summary: Subscribe to message events
      description: |
        Save the secret returned when the webhook is created. Verify
        X-Chatwoot-Signature as an HMAC-SHA256 over `<timestamp>.<raw body>`,
        and deduplicate deliveries by X-Chatwoot-Delivery.
      parameters:
        - $ref: '#/components/parameters/AccountId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [webhook]
              properties:
                webhook:
                  $ref: '#/components/schemas/CreateWebhook'
            example:
              webhook:
                name: Setrio delivery events
                url: https://medical.setrio.ro/webhooks/bow-chat
                subscriptions: [message_created, message_updated]
      responses:
        '200':
          description: Webhook created; the response includes its signing secret
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    UserApiKey:
      type: apiKey
      in: header
      name: api_access_token
      description: A dedicated Bow Chat integration token. Never place it in browser code or a URL.
  parameters:
    AccountId:
      name: account_id
      in: path
      required: true
      schema:
        type: integer
    ContactId:
      name: contact_id
      in: path
      required: true
      schema:
        type: integer
    ConversationId:
      name: conversation_id
      in: path
      required: true
      description: The account-scoped conversation display ID returned by Bow Chat.
      schema:
        type: integer
  schemas:
    Inbox:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        channel_type:
          type: string
      additionalProperties: true
    CreateContact:
      type: object
      required: [inbox_id]
      properties:
        inbox_id:
          type: integer
        name:
          type: string
        phone_number:
          type: string
          description: E.164 format is recommended.
        email:
          type: string
          format: email
        identifier:
          type: string
          description: Stable contact ID from the integrating system.
        additional_attributes:
          type: object
          additionalProperties: true
    CreateConversation:
      type: object
      required: [source_id]
      properties:
        source_id:
          type: string
          description: Use the source_id returned by contactable_inboxes.
        inbox_id:
          type: integer
        contact_id:
          type: integer
        status:
          type: string
          enum: [open, resolved, pending]
        custom_attributes:
          type: object
          additionalProperties: true
    Conversation:
      type: object
      properties:
        id:
          type: integer
          description: Account-scoped display ID used by conversation API paths.
        account_id:
          type: integer
        inbox_id:
          type: integer
      additionalProperties: true
    CreateMessage:
      type: object
      required: [content]
      properties:
        content:
          type: string
        message_type:
          type: string
          enum: [outgoing, incoming]
          default: outgoing
        private:
          type: boolean
          default: false
        template_params:
          $ref: '#/components/schemas/TemplateParams'
    TemplateParams:
      type: object
      required: [name, category, language, processed_params]
      properties:
        name:
          type: string
        category:
          type: string
          enum: [UTILITY, MARKETING, AUTHENTICATION]
        language:
          type: string
          description: Language code configured for the approved template.
        processed_params:
          type: object
          additionalProperties: true
    Message:
      type: object
      properties:
        id:
          type: integer
        content:
          type: string
        account_id:
          type: integer
        inbox_id:
          type: integer
        conversation_id:
          type: integer
        message_type:
          type: integer
        created_at:
          type: integer
        status:
          type: [string, 'null']
          enum: [sent, delivered, read, failed, null]
        source_id:
          type: [string, 'null']
        external_error:
          type: [string, 'null']
      additionalProperties: true
    CreateWebhook:
      type: object
      required: [url, subscriptions]
      properties:
        name:
          type: string
        url:
          type: string
          format: uri
        inbox_id:
          type: integer
        subscriptions:
          type: array
          minItems: 1
          items:
            type: string
            enum:
              - conversation_created
              - conversation_status_changed
              - conversation_updated
              - message_created
              - message_updated
              - contact_created
              - contact_updated
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
    Unauthorized:
      description: Missing or invalid API token
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
    Forbidden:
      description: The token does not have access to the account or resource
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
    NotFound:
      description: Account-scoped resource not found
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
