openapi: 3.1.0
info:
  title: Webhook API
  description: |
    Webhooks are a way to send real-time data from one application to another whenever a specific event occurs. Our specific implementation sends data using the POST method to a specified endpoint. Authentication of the request or customizing headers is not supported.

    ## Key Features

    - **Multiple Webhooks per Workspace**: Create multiple webhooks within a single workspace, each supporting one specific event.
    - **Customizable Limits**: The default limit on the number of webhooks per workspace is 10. To increase this limit, a paid add-on is available. Please contact support for more information.
    - **Audit log**: An audit log for all changes in webhook endpoints is available on the Webhooks management display.
    - **Execution log**: Execution logs for each webhook can be downloaded from the Webhooks management page. Up to 1000 execution entries are stored for a maximum of 10 days.
    - **Error Notification for Webhook Endpoint Failures**: An email notification is sent to workspace owner in case of multiple successive errors for a specific webhook endpoint. However, the webhook will not be disabled.
    
    ### Note: 
    - All message and chat events are triggered for all WhatsApp accounts connected to the workspace, including those initiated from a mobile app or another linked device.
    The incoming/outgoing direction is relative to the WhatsApp account as a whole, not to any specific session (such as a mobile app, WhatsApp Web, or TimelinesAI connection).
    - whatsapp:account:disconnected is triggered when the WhatsApp account is permanently disconnected from the workspace, while whatsapp:account:suspended is triggered when message syncing is temporary paused due to subscription cancellation or downgrade (it will not be triggered for disconnection).
    We recommend to subscribe for both events to ensure that messaging operation is not interrupted.
    - IDs of objects returned by Webhooks can be used in conjunction with TimelinesAI Public API and Zapier to fetch additional data or perform actions.
  version: 2.0.0

webhooks:
  message:new:
    post:
      summary: Triggered when there is a new message.
      tags:
        - messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  message:sent:new:
    post:
      summary: Triggered when a new outgoing message.
      tags:
        - messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  message:received:new:
    post:
      summary: Triggered when there is a new incoming message.
      tags:
        - messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  whatsapp:account:connected:
    post:
      summary: Triggered when WhatsApp account was (re)connected.
      tags:
        - whatsapp_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  whatsapp:account:disconnected:
    post:
      summary: Triggered when WhatsApp account was disconnected.
      tags:
        - whatsapp_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  whatsapp:account:suspended:
    post:
      summary: Triggered when a WhatsApp account message syncing is suspended for a reason such as subscription cancellation or downgrade.
      tags:
        - whatsapp_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  whatsapp:account:resumed:
    post:
      summary: Triggered when a WhatsApp account message syncing is resumed.
      tags:
        - whatsapp_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  chat:new:
    post:
      summary:  Triggered when there is a new direct or group chat.
      tags:
        - chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  chat:incoming:new:
    post:
      summary: Triggered when there is a new incoming direct chat.
      tags:
        - chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  chat:outgoing:new:
    post:
      summary: Triggered when there is a new outgoing direct chat.
      tags:
        - chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  chat:responsible:assigned:
    post:
      summary: Triggered when a chat was (re)assigned to a workspace member.
      tags:
        - chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  chat:responsible:unassigned:
    post:
      summary: Triggered when a chat was unassigned.
      tags:
        - chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  call:incoming:missed:
    post:
      summary: Triggered when an incoming WhatsApp call was missed.
      tags:
        - calls
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  call:incoming:ended:
    post:
      summary: Triggered when an incoming WhatsApp call ended.
      tags:
        - calls
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  call:outgoing:ended:
    post:
      summary: Triggered when an outgoing WhatsApp call ended.
      tags:
        - calls
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  message:reaction:
    post:
      summary: Triggered when a WhatsApp message reaction is set or cleared.
      tags:
        - messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReactionData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:message:received:
    post:
      summary: Triggered when a new WABA message is received from a contact.
      tags:
        - waba_messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaMessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:message:delivered:
    post:
      summary: Triggered when an outbound WABA message is delivered.
      tags:
        - waba_messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaMessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:message:failed:
    post:
      summary: Triggered when an outbound WABA message fails to send.
      tags:
        - waba_messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaMessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:message:read:
    post:
      summary: Triggered when an outbound WABA message is read.
      tags:
        - waba_messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaMessageData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:account:active:
    post:
      summary: Triggered when a WABA account becomes active.
      tags:
        - waba_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaAccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:account:disabled:
    post:
      summary: Triggered when a WABA account is disabled.
      tags:
        - waba_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaAccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:account:disconnected:
    post:
      summary: Triggered when a WABA account is disconnected (removed).
      tags:
        - waba_accounts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaAccountData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:template:approved:
    post:
      summary: Triggered when a WABA template is approved by Meta.
      tags:
        - waba_templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaTemplateData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:template:rejected:
    post:
      summary: Triggered when a WABA template is rejected by Meta.
      tags:
        - waba_templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaTemplateData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:template:disabled:
    post:
      summary: Triggered when a WABA template is disabled / pending deletion.
      tags:
        - waba_templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaTemplateData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:incoming:
    post:
      summary: Triggered when there is a new incoming WABA chat.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:outgoing:
    post:
      summary: Triggered when there is a new outgoing WABA chat.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:assigned:
    post:
      summary: Triggered when a WABA chat is (re)assigned to a workspace member.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:unassigned:
    post:
      summary: Triggered when a WABA chat is unassigned.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:closed:
    post:
      summary: Triggered when a WABA chat is closed.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

  waba:chat:reopened:
    post:
      summary: Triggered when a WABA chat is reopened.
      tags:
        - waba_chats
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WabaChatData'
      responses:
        '200':
          description: 'Receiver accepted the event'

components:
  schemas:
# Main data objects
    ChatData:
      type: object
      required:
        - event_type
        - chat
        - whatsapp_account
      properties:
        event_type:
          type: string
          description: Webhook code name
          example: chat:new
          enum:
            - chat:new
            - chat:incoming:new
            - chat:outgoing:new
            - chat:responsible:assigned
            - chat:responsible:unassigned
        chat:
          $ref: '#/components/schemas/ChatDataInfo'
        whatsapp_account:
          $ref: '#/components/schemas/ChatDataWhatsappAccountInfo'

    AccountData:
      type: object
      required:
        - event_type
        - whatsapp_account
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: whatsapp:account:connected
          enum:
            - whatsapp:account:connected
            - whatsapp:account:disconnected
            - whatsapp:account:suspended
            - whatsapp:account:resumed
        whatsapp_account:
          $ref: '#/components/schemas/AccountDataWhatsappAccountInfo'

    MessageData:
      type: object
      required:
        - event_type
        - chat
        - whatsapp_account
        - message
      properties:
        event_type:
          type: string
          description: Webhook event name
          enum:
            - message:new
            - message:sent:new
            - message:received:new
          example: message:new
        chat:
          $ref: '#/components/schemas/MessageDataChatInfo'
        whatsapp_account:
          $ref: '#/components/schemas/MessageDataWhatsappAccountInfo'
        message:
          $ref: '#/components/schemas/MessageDataInfo'

    CallData:
      type: object
      required:
        - event_type
        - chat
        - whatsapp_account
        - call_details
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: call:incoming:missed
          enum:
            - call:incoming:missed
            - call:incoming:ended
            - call:outgoing:ended
        chat:
          $ref: '#/components/schemas/CallDataChatInfo'
        whatsapp_account:
          $ref: '#/components/schemas/CallDataWhatsappAccountInfo'
        call_details:
          $ref: '#/components/schemas/CallDetailsInfo'

    ReactionData:
      type: object
      required:
        - event_type
        - chat
        - whatsapp_account
        - reaction
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: message:reaction
          enum:
            - message:reaction
        chat:
          $ref: '#/components/schemas/ReactionDataChatInfo'
        whatsapp_account:
          $ref: '#/components/schemas/ReactionDataWhatsappAccountInfo'
        reaction:
          $ref: '#/components/schemas/ReactionInfo'

    WabaMessageData:
      type: object
      required:
        - event_type
        - account
        - chat
        - message
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: waba:message:received
          enum:
            - waba:message:received
            - waba:message:delivered
            - waba:message:failed
            - waba:message:read
        account:
          $ref: '#/components/schemas/WabaMessageAccountInfo'
        chat:
          $ref: '#/components/schemas/WabaMessageChatInfo'
        message:
          $ref: '#/components/schemas/WabaMessageInfo'

    WabaChatData:
      type: object
      required:
        - event_type
        - chat
        - account
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: waba:chat:incoming
          enum:
            - waba:chat:incoming
            - waba:chat:outgoing
            - waba:chat:assigned
            - waba:chat:unassigned
            - waba:chat:closed
            - waba:chat:reopened
        chat:
          $ref: '#/components/schemas/WabaChatInfo'
        account:
          $ref: '#/components/schemas/WabaBasicAccountInfo'
        responsible:
          $ref: '#/components/schemas/WabaResponsibleInfo'
          description: >
            Present (non-null) only for waba:chat:assigned; null/absent for the
            other WABA chat events.

    WabaAccountData:
      type: object
      required:
        - event_type
        - account
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: waba:account:active
          enum:
            - waba:account:active
            - waba:account:disabled
            - waba:account:disconnected
        account:
          $ref: '#/components/schemas/WabaAccountInfo'

    WabaTemplateData:
      type: object
      required:
        - event_type
        - template
      properties:
        event_type:
          type: string
          description: Webhook event name
          example: waba:template:approved
          enum:
            - waba:template:approved
            - waba:template:rejected
            - waba:template:disabled
        template:
          $ref: '#/components/schemas/WabaTemplateInfo'

# Subobjects
    AccountDataWhatsappAccountInfo:
      type: object
      required:
        - id
        - phone
        - connected_on
        - status
        - account_name
        - owner_name
        - owner_email
      properties:
        id:
          type: string
          description: WhatsApp account global ID
          example: 123456789@s.whatsapp.net
        phone:
          type: string
          description: Phone number associated with the WhatsApp account
          example: "+123456789"
        connected_on:
          type: string
          example: 2024-01-08 10:35:18 +0200
        disconnected_on:
          type: string
          example: 2024-01-08 10:35:18 +0200
        status:
          type: string
          example: active
        account_name:
          type: string
          description: Name of the WhatsApp account
          example: Smith
        owner_name:
          type: string
          example: John Smith
        owner_email:
          type: string
          example: john-smith@example.com

    PartyInfo:
      type: object
      required:
        - full_name
      properties:
        full_name:
          type: string
          example: John Smith
        phone:
          type: string
          example: "+123456789"

    AttachmentInfo:
      type: object
      required:
        - temporary_download_url
        - filename
        - size
        - mimetype
      properties:
        temporary_download_url:
          type: string
          example: https://example.s3.amazonaws.com/att/...
          description: valid for 15 minutes
        filename:
          type: string
          example: example.doc
        size:
          type: integer
          example: 1234567
        mimetype:
          type: string
          example: application/msword

    AttachmentList:
      type: array
      items:
        $ref: '#/components/schemas/AttachmentInfo'

    MessageDataInfo:
      type: object
      required:
        - text
        - direction
        - origin
        - timestamp
        - received_timestamp
        - message_uid
        - sender
        - recipient

      properties:
        text:
          type: string
          example: Sending some example document to you
        direction:
          type: string
          example: sent
        origin:
          example: Public API
          type: string
        timestamp:
          description: message creation timestamp, WhatsApp message time
          example: 2023-06-18 15:19:23 +0300
          type: string
        received_timestamp:
          description: message creation timestamp in TimelinesAI, in ISO format with timezone
          example: 2023-06-18 14:39:25 +0300
          type: string
        message_uid:
          type: string
          example: c7ec509d-0171-1ead-a84b-c6943a644768
        reply_to_uid:
          type: string
          example: c7ec509d-0171-1ead-a84b-c6943a644768
        sender:
          $ref: '#/components/schemas/PartyInfo'
        recipient:
          $ref: '#/components/schemas/PartyInfo'
        attachments:
          $ref: '#/components/schemas/AttachmentList'


    MessageDataWhatsappAccountInfo:
      type: object
      required:
        - full_name
        - email
        - phone
      properties:
        full_name:
          type: string
          example: Agent Brown
        email:
          type: string
          example: agent-brown@example.com
        phone:
          type: string
          example: "+123456789"

    MessageDataChatInfo:
      type: object
      required:
        - full_name
        - chat_url
        - chat_id
        - is_group
        - phone
      properties:
        full_name:
          type: string
          example: Agent Smith
        chat_url:
          type: string
          example: https://app.timelines.ai/chat/123456/messages/
        chat_id:
          type: integer
          example: 123456
        is_group:
          type: boolean
          example: false
        phone:
          type: string
          example: "+123456789"
        responsible_name:
          type: string
          example: Agent Brown
        responsible_email:
          type: string
          example: agent-brown@example.com

    ChatDataWhatsappAccountInfo:
      type: object
      required:
        - id
        - phone
        - connected_on
        - status
        - account_name
        - owner_email
        - owner_name
      properties:
        id:
          type: string
          example: 123456789@s.whatsapp.net
        phone:
          type: string
          example: "+123456789"
        connected_on:
          type: string
          example: 2024-01-08 10:35:18 +0200
        disconnected_on:
          type: string
          example: 2024-01-08 10:35:18 +0200
        status:
          type: string
          example: active
        account_name:
          type: string
          example: Some account
        owner_name:
          type: string
          example: Agent Smith
        owner_email:
          type: string
          example: agent-smith@example.com


    ChatDataInfo:
      type: object
      required:
        - id
        - name
        - phone
        - jid
        - is_group
        - closed
        - read
        - labels
        - unattended_customer
        - chatgpt_autoresponse_enabled
        - whatsapp_account_id
        - chat_url
        - created_timestamp
      properties:
        id:
          type: integer
          example: 123456
        name:
          type: string
          example: John Smith
        phone:
          type: string
          example: "+123456789"
        jid:
          type: string
          example: "123456789@s.whatsapp.net"
        is_group:
          type: boolean
          example: false
        closed:
          type: boolean
          example: false
        read:
          type: boolean
          example: false
        labels:
          type: array
          items:
            type: string
        unattended_customer:
          type: boolean
          example: false
        chatgpt_autoresponse_enabled:
          type: boolean
          example: false
        whatsapp_account_id:
          type: string
          example: 123456789@s.whatsapp.net
        chat_url:
          type: string
          example: https://app.timelines.ai/chat/123456/messages/
        created_timestamp:
          type: string
          example: 2024-01-08 10:35:18 +0200
        last_message_uid:
          type: string
          example: afa9d4dd-978d-4a14-aa1b-bd65c272e645
        last_message_timestamp:
          type: string
          example: 2024-01-08 10:35:18 +0200
        responsible_name:
          type: string
          example: Agent Brown
        responsible_email:
          type: string
          example: agent-brown@example.com
        previous_responsible_name:
          type: string
          example: Agent Jones
        previous_responsible_email:
          type: string
          example: agent-jones@example.com

    CallDataChatInfo:
      type: object
      required:
        - full_name
        - chat_url
        - chat_id
        - chat_type
        - platform
        - phone
      properties:
        full_name:
          type: string
          example: Agent Smith
        chat_url:
          type: string
          example: https://app.timelines.ai/chat/123456/messages/
        chat_id:
          type: integer
          example: 123456
        chat_type:
          type: string
          description: direct or group
          example: direct
          enum:
            - direct
            - group
        platform:
          type: string
          description: whatsapp
          example: whatsapp
          enum:
            - whatsapp
        phone:
          type: string
          description: Bare digits (no + prefix) for direct chats; empty string for groups.
          example: "380739833532"
        responsible_name:
          type: string
          example: Agent Brown
        responsible_email:
          type: string
          example: agent-brown@example.com

    CallDataWhatsappAccountInfo:
      type: object
      required:
        - whatsapp_account_wid
        - full_name
        - email
        - phone
      properties:
        whatsapp_account_wid:
          type: string
          description: WhatsApp account JID
          example: 123456789@s.whatsapp.net
        full_name:
          type: string
          example: Agent Brown
        email:
          type: string
          example: agent-brown@example.com
        phone:
          type: string
          example: "+123456789"

    CallDetailsInfo:
      type: object
      required:
        - direction
        - is_video
        - status
        - timestamp
        - message_uid
        - caller
        - recipient
      properties:
        duration:
          type:
            - integer
            - "null"
          description: Call duration in seconds, null if not available
          example: 120
        direction:
          type: string
          description: incoming or outgoing
          example: incoming
        is_video:
          type: boolean
          example: false
        status:
          type: string
          description: |
            Allowed values per event_type:
            - call:incoming:missed -> Missed
            - call:incoming:ended -> Answered | Rejected
            - call:outgoing:ended -> Ended | No Answer | Rejected
          example: Missed
          enum:
            - Missed
            - Answered
            - Rejected
            - No Answer
            - Ended
        timestamp:
          type: string
          example: 2024-01-08 10:35:18 +0200
        message_uid:
          type: string
          example: c7ec509d-0171-1ead-a84b-c6943a644768
        caller:
          $ref: '#/components/schemas/PartyInfo'
        recipient:
          $ref: '#/components/schemas/PartyInfo'

    ReactionDataChatInfo:
      type: object
      required:
        - full_name
        - chat_url
        - chat_id
        - chat_type
        - platform
        - phone
      properties:
        full_name:
          type: string
          example: Agent Smith
        chat_url:
          type: string
          example: https://app.timelines.ai/chat/123456/messages/
        chat_id:
          type: integer
          example: 123456
        chat_type:
          type: string
          description: "Chat type: direct or group"
          example: direct
          enum:
            - direct
            - group
        platform:
          type: string
          description: Messaging platform
          example: whatsapp
          enum:
            - whatsapp
        phone:
          type: string
          description: Bare digits (no + prefix) for direct chats; empty string for groups.
          example: "380739833532"
        responsible_name:
          type: string
          example: Agent Brown
        responsible_email:
          type: string
          example: agent-brown@example.com

    ReactionDataWhatsappAccountInfo:
      allOf:
        - $ref: '#/components/schemas/MessageDataWhatsappAccountInfo'
        - type: object
          required:
            - whatsapp_account_wid
          properties:
            whatsapp_account_wid:
              type: string
              description: WhatsApp account WID
              example: 123456789@s.whatsapp.net

    ReactorInfo:
      type: object
      required:
        - full_name
        - phone
      properties:
        full_name:
          type: string
          example: John Smith
        phone:
          type: string
          example: "+123456789"

    ReactionInfo:
      type: object
      required:
        - message_uid
        - action
        - emoji
        - timestamp
        - reactions
      properties:
        message_uid:
          type: string
          description: UID of the message that was reacted to
          example: c7ec509d-0171-1ead-a84b-c6943a644768
        action:
          type: string
          description: "Reaction action: set or clear"
          example: set
          enum:
            - set
            - clear
        emoji:
          type: string
          description: Emoji reaction
          example: "👍"
        reactor:
          $ref: '#/components/schemas/ReactorInfo'
        timestamp:
          type: string
          example: 2024-01-08 10:35:18 +0200
        reactions:
          type: object
          description: Current reaction counts as integer values
          additionalProperties:
            type: integer
          example:
            👍: 2
            ❤️: 1

# WABA subobjects
    WabaMessageAccountInfo:
      type: object
      required:
        - id
        - meta_phone_id
        - meta_waba_id
        - account_name
      properties:
        id:
          type: integer
          description: Internal WABA account id
          example: 4821
        meta_phone_id:
          type: string
          example: "109998887776665"
        meta_waba_id:
          type: string
          example: "203344556677889"
        phone:
          type: string
          example: "+15559876543"
        account_name:
          type: string
          example: Sales Bot

    WabaBasicAccountInfo:
      type: object
      required:
        - id
        - meta_phone_id
        - meta_waba_id
      properties:
        id:
          type: integer
          example: 4821
        meta_phone_id:
          type: string
          example: "109876543210987"
        meta_waba_id:
          type: string
          example: "102233445566778"

    WabaAccountInfo:
      type: object
      required:
        - id
        - meta_phone_id
        - meta_waba_id
        - state
      properties:
        id:
          type: integer
          example: 4821
        meta_phone_id:
          type: string
          example: "109998887776665"
        meta_waba_id:
          type: string
          example: "203344556677889"
        display_phone_number:
          type: string
          example: "+1 555 010 1234"
        state:
          type: string
          description: >
            Raw WABA account lifecycle state. Note this differs from the
            waba:account:disconnected event name: the underlying state value for a
            disconnected account is `removed`, not `disconnected`.
          example: active
          enum:
            - active
            - disabled
            - removed

    WabaMessageChatInfo:
      type: object
      required:
        - id
        - waba_account_id
        - closed
      properties:
        id:
          type: integer
          description: TimelinesAI chat id
          example: 90155
        waba_account_id:
          type: integer
          example: 4821
        closed:
          type: boolean
          example: false
        service_window_is_open:
          type: boolean
          description: >
            Whether the 24h customer service window is currently open. Null when
            no incoming message has been recorded for this chat yet.
          example: true
        service_window_expires_at:
          type: string
          description: When the current service window closes, in the workspace timezone.
          example: 2024-01-08 10:35:18 +0200

    WabaChatInfo:
      type: object
      required:
        - id
        - waba_account_id
      properties:
        id:
          type: integer
          description: TimelinesAI chat id
          example: 90155
        waba_account_id:
          type: integer
          example: 4821

    WabaResponsibleInfo:
      type: object
      properties:
        name:
          type: string
          example: Agent Brown
        email:
          type: string
          example: agent-brown@example.com

    WabaMessageTemplateInfo:
      type: object
      description: Present only when the message was sent from a template.
      required:
        - name
      properties:
        id:
          type: integer
          description: Internal template id, when the template could be resolved locally.
          example: 501
        name:
          type: string
          example: order_confirmation

    WabaMessageFailureReason:
      type: object
      required:
        - code
        - title
        - details
      properties:
        code:
          oneOf:
            - type: integer
            - type: string
              enum:
                - ''
          example: 131047
        title:
          type: string
          example: "Re-engagement message"
        details:
          type: string
          example: "Message failed to send outside the 24 hour window."

    WabaMessageInfo:
      type: object
      required:
        - message_uid
        - direction
        - status
        - timestamp
      properties:
        message_uid:
          type: string
          example: c7ec509d-0171-1ead-a84b-c6943a644768
        direction:
          type: string
          description: sent or received
          example: sent
        status:
          type: string
          example: Delivered
        timestamp:
          type: string
          example: "2026-06-24 10:15:30 +0000"
        received_timestamp:
          type: string
          example: "2026-06-24 10:15:31 +0000"
        text:
          type: string
          example: Hi, is this still available?
        origin:
          type: string
          example: WhatsApp
        sender:
          $ref: '#/components/schemas/PartyInfo'
        recipient:
          $ref: '#/components/schemas/PartyInfo'
        attachments:
          $ref: '#/components/schemas/AttachmentList'
        template:
          $ref: '#/components/schemas/WabaMessageTemplateInfo'
        failure_reason:
          description: Required for `waba:message:failed`; omitted for `waba:message:received`, `waba:message:delivered`, and `waba:message:read`.
          $ref: '#/components/schemas/WabaMessageFailureReason'

    WabaTemplateInfo:
      type: object
      required:
        - id
        - name
        - status
        - meta_waba_id
        - accounts
      properties:
        id:
          type: integer
          example: 501
        name:
          type: string
          example: order_confirmation_v2
        status:
          type: string
          description: Meta's template status, returned verbatim.
          example: APPROVED
        parameter_format:
          type: string
          example: NAMED
        meta_waba_id:
          type: string
          example: "102233445566778"
        accounts:
          type: array
          description: Internal WabaAccount ids under the same WABA profile.
          items:
            type: integer
          example: [4821, 4822]
