ZenZap Topics (group chats/channels/conversations) API

Operations for managing topics (group chats/channels/conversations)

OpenAPI Specification

zenzap-topics-group-chats-channels-conversations-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Zenzap External Integration Agentic Topics (group chats/channels/conversations) API
  description: "API for external applications to integrate with Zenzap.\n## Getting Started\nWelcome to the Zenzap External Integration API documentation. This API is used to integrate with Zenzap.\nAs a context we would like to familiarize you with the Zenzap platform and how it works.\nZenzap is a platform for creating and managing topics and messages.\nTopics (Zenzap term for group chats/channels/conversations) are used to create and manage conversations with your team. Topics are used to group messages and tasks together.\nMessages are used to send and receive messages with your team.\nTasks are used to create and manage tasks with your team.\nMembers are used to manage your team members.\nAPI keys are used to authenticate your requests to the Zenzap API.\nAPI keys are created and managed by the Zenzap admin user.\n\nWhen you create a new API key, it would create a new bot user in Zenzap, on which behalf you can send messages, create topics, create tasks and manage members.\nAll actions you perform with the API key will be performed on behalf of the bot user.\nThe bot can be used within the scope of your organization. You can create topics, send messages, create tasks and manage members on behalf of the bot.\n1. On a Zenzap admin user, go to https://app.zenzap.co/console\n2. Create a new API key with the needed permissions\n3. Copy the API key and secret from the API key settings\n4. For each request:\n   - Add the Authorization header with your API key\n   - Generate a Unix timestamp in milliseconds\n   - Calculate the HMAC-SHA256 signature:\n     - For POST/PUT/PATCH/DELETE: Sign `{timestamp}.{body}`\n     - For GET: Sign `{timestamp}.{uri}` (e.g., `/v2/members?limit=10`)\n   - Add the X-Signature header with the hex-encoded signature\n   - Add the X-Timestamp header with the timestamp used in the payload\n\n## Authentication\nAll API endpoints require two forms of authentication:\n\n1. **Bearer Token**: Include your API key in the Authorization header:\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\n2. **Request Signing**: Include an HMAC signature and timestamp in headers:\n```\nX-Signature: <HMAC-SHA256 hex-encoded signature>\nX-Timestamp: <Unix timestamp in milliseconds>\n```\nThe signature includes a timestamp for replay protection. Requests older than 5 minutes are rejected.\n\nThe signature payload differs by HTTP method:\n- **POST/PUT/PATCH/DELETE requests**: Sign `{timestamp}.{body}`\n- **GET requests**: Sign `{timestamp}.{uri}`\n\nThe signature is calculated using HMAC-SHA256 with your API secret.\n\n  **How to calculate:**\n  1. Get the current Unix timestamp in milliseconds\n  2. Determine the payload:\n      - **POST/PUT/PATCH/DELETE**: Use `{timestamp}.{body}` (e.g., `1699564800000.{\"topicId\":\"123\"}`)\n      - **GET**: Use `{timestamp}.{uri}` (e.g., `1699564800000./v2/members?limit=10`)\n  3. Calculate HMAC-SHA256 of the payload using your API secret\n  4. Hex-encode the result (64 character lowercase string)\n  5. Include timestamp in X-Timestamp header\n\n  **Example (Python):**\n  ```python\n  import json\n  import hmac\n  import hashlib\n  import time\n  import requests\n\n  def create_topic(name: str, members: list[str], description: str = None, external_id: str = None) -> dict:\n      \"\"\"Create a topic in Zenzap with HMAC signature and replay protection.\"\"\"\n\n      # Build request body\n      body = {\n          \"name\": name,\n          \"members\": members,\n      }\n      if description:\n          body[\"description\"] = description\n      if external_id:\n          body[\"externalId\"] = external_id\n\n      # Serialize body (no spaces for consistent signing)\n      body_json = json.dumps(body, separators=(\",\", \":\"))\n\n      # Get timestamp for replay protection\n      timestamp = int(time.time() * 1000)  # Unix milliseconds\n\n      # Create HMAC-SHA256 signature with timestamp\n      signature_payload = f\"{timestamp}.{body_json}\"\n      signature = hmac.new(\n          API_SECRET.encode(),\n          signature_payload.encode(),\n          hashlib.sha256\n      ).hexdigest()\n\n      # Make request\n      headers = {\n          \"Authorization\": f\"Bearer {API_KEY}\",\n          \"Content-Type\": \"application/json\",\n          \"X-Signature\": signature,\n          \"X-Timestamp\": str(timestamp),\n      }\n\n      response = requests.post(f\"{BASE_URL}/v2/topics\", headers=headers, data=body_json)\n      response.raise_for_status()\n      return response.json()\n  ```\n\n  **Note:** Our API documentation tools cannot automatically generate HMAC signatures. You will need to calculate this manually or use a tool like Postman with pre-request scripts.\n\n\n## Rate Limits\nAPI requests are rate limited per organization. Contact support for specific limits.\n"
  version: 2.0.0
  contact:
    name: Zenzap Support
    url: https://zenzap.co/support
servers:
- url: https://api.zenzap.co
  description: Production server
security:
- bearerAuth: []
  hmacSignature: []
- oauth2ClientCredentials: []
tags:
- name: Topics (group chats/channels/conversations)
  description: Operations for managing topics (group chats/channels/conversations)
paths:
  /v2/topics:
    get:
      summary: List topics
      description: 'Get a paginated list of all topics and direct messages where your API key bot is a member.

        Results are sorted by creation date (newest first).


        Pagination:

        - `limit`: default `50`, max `100`

        - `cursor`: opaque cursor from the previous response (`nextCursor`)

        '
      operationId: listTopics
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:list
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: limit
        in: query
        description: 'Maximum number of topics to return (default: 50, max: 100)'
        required: false
        schema:
          type: integer
          format: int64
          minimum: 1
          maximum: 100
          default: 50
      - name: cursor
        in: query
        description: Opaque cursor from a previous `nextCursor` value.
        required: false
        schema:
          type: string
      responses:
        '200':
          description: Topics list retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicsListResponse'
              example:
                topics:
                - id: 550e8400-e29b-41d4-a716-446655440000
                  name: Project Updates
                  description: Discussion for project milestones
                  type: topic
                  properties: []
                  members:
                  - 550e8400-e29b-41d4-a716-446655440001
                  - 550e8400-e29b-41d4-a716-446655440002
                  - b@660e8400-e29b-41d4-a716-446655440003
                  createdAt: 1699564800000
                  updatedAt: 1699564800000
                  externalId: project-alpha
                - id: 550e8400-e29b-41d4-a716-446655440010
                  name: Company Announcements
                  type: topic
                  properties:
                  - announcement
                  members:
                  - 550e8400-e29b-41d4-a716-446655440001
                  - b@660e8400-e29b-41d4-a716-446655440003
                  createdAt: 1699564900000
                  updatedAt: 1699564900000
                - id: 550e8400-e29b-41d4-a716-446655440020
                  name: John Doe
                  type: dm
                  properties: []
                  members:
                  - 550e8400-e29b-41d4-a716-446655440001
                  - b@660e8400-e29b-41d4-a716-446655440003
                  createdAt: 1699565000000
                  updatedAt: 1699565000000
                nextCursor: eyJ0IjoxNjk5NTY1MDAwMDAwLCJpZCI6IjU1MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAyMCJ9.abc123
                hasMore: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      summary: Create a topic
      description: 'Create a new topic with specified members. Your API key bot will automatically be added as a member.


        Limits:

        - topic name is limited to 64 characters

        - topic description is limited to 10000 characters

        - maximum 100 members per topic

        - you can only add members that are already in your organization

        - topic externalId is limited to 100 characters

        - externalId must be unique per bot - you cannot create multiple topics with the same externalId

        '
      operationId: createTopic
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:write
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopicCreateRequest'
            examples:
              basic:
                summary: Basic topic
                value:
                  name: Project Updates
                  members:
                  - 550e8400-e29b-41d4-a716-446655440001
                  - 550e8400-e29b-41d4-a716-446655440002
              withDescription:
                summary: Topic with description
                value:
                  name: Marketing Campaign
                  description: Discussion for Q4 marketing campaign
                  members:
                  - 550e8400-e29b-41d4-a716-446655440001
                  - 550e8400-e29b-41d4-a716-446655440002
                  - 550e8400-e29b-41d4-a716-446655440003
                  externalId: campaign-q4-2024
      responses:
        '201':
          description: Topic created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicCreateResponse'
              example:
                id: 770e8400-e29b-41d4-a716-446655440002
                name: Project Updates
                members:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
                - b@660e8400-e29b-41d4-a716-446655440003
                externalId: b@660e8400-e29b-41d4-a716-446655440003:campaign-q4-2024
                createdAt: 1699564800000
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/topics/external/{externalId}:
    get:
      summary: Get topic by external ID
      description: 'Get details of a specific topic by its external ID (set when creating the topic).


        **Authorization:** Your API key bot must be a member of the topic to access its details.


        **Note:** For security reasons, a 404 response is returned both when the topic does not exist

        and when your bot is not a member of the topic.


        ## Deep linking to topics


        You can open Zenzap directly to a topic using its external ID by adding a query parameter to the Zenzap app URL.


        | Component | Value |

        |-----------|-------|

        | Base URL | **https://app.zenzap.co** |

        | Query parameter | **external_topic** |

        | Parameter value | Your external ID |


        For example, use **https://app.zenzap.co?external_topic=project-123** to link directly to a topic with external ID "project-123".


        This is useful for creating links from your application that navigate users directly to the relevant conversation in Zenzap.


        ### Short vs fully qualified external ID


        You can use either the **short external ID** (the value you passed when creating the topic) or the **fully qualified external ID**.


        For security purposes, if multiple bots create topics with the same external ID, each topic is internally prefixed with the bot ID in the format **bot_id:external_id**. The bot ID follows the format `b@<uuid>` (e.g., `b@660e8400-e29b-41d4-a716-446655440003`). To avoid ambiguity, use the fully qualified format like **https://app.zenzap.co?external_topic=b@660e8400-e29b-41d4-a716-446655440003:project-123**.


        | Format | Example URL |

        |--------|-------------|

        | Short | **https://app.zenzap.co?external_topic=project-123** |

        | Fully qualified | **https://app.zenzap.co?external_topic=b@660e8400-e29b-41d4-a716-446655440003:project-123** |


        ### Multiple matches


        If you use the short external ID and multiple bots have created topics with the same external ID, the user will see a selection screen to choose the correct topic:


        ![Topic selection screen](/images/topic_selection.jpg)


        ### Platform availability


        Deep linking is currently supported on **Web** and **Windows** versions of Zenzap.

        '
      operationId: getTopicByExternalId
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:read
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: externalId
        in: path
        required: true
        description: The external ID of the topic to retrieve
        schema:
          type: string
          maxLength: 100
        example: project-alpha
      responses:
        '200':
          description: Topic details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicGetResponse'
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                name: Project Updates
                description: Discussion for project milestones
                memberIds:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
                - b@660e8400-e29b-41d4-a716-446655440003
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/topics/{topicId}:
    get:
      summary: Get topic details
      description: 'Get details of a specific topic including its name, description, and member IDs.


        **Authorization:** Your API key bot must be a member of the topic to access its details.


        **Note:** For security reasons, a 404 response is returned both when the topic does not exist

        and when your bot is not a member of the topic.

        '
      operationId: getTopic
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:read
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: topicId
        in: path
        required: true
        description: The ID of the topic to retrieve
        schema:
          type: string
          format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Topic details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicGetResponse'
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                name: Project Updates
                description: Discussion for project milestones
                memberIds:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
                - b@660e8400-e29b-41d4-a716-446655440003
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    patch:
      summary: Update a topic
      description: 'Update the name and/or description of a topic.


        **Authorization:** Your API key bot must be a member of the topic to update it.


        **Validation:** At least one of `name` or `description` must be provided.


        **Note:** For security reasons, a 404 response is returned both when the topic does not exist

        and when your bot is not a member of the topic.


        Limits:

        - topic name is limited to 64 characters

        - topic description is limited to 10000 characters

        '
      operationId: updateTopic
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:write
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: topicId
        in: path
        required: true
        description: The ID of the topic to update
        schema:
          type: string
          format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopicPatchRequest'
            examples:
              updateName:
                summary: Update topic name
                value:
                  name: New Project Name
              updateDescription:
                summary: Update topic description
                value:
                  description: Updated description for the project
              updateBoth:
                summary: Update both name and description
                value:
                  name: Renamed Project
                  description: New description for the renamed project
      responses:
        '200':
          description: Topic updated successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/topics/{topicId}/messages:
    get:
      summary: Get topic messages
      description: 'Get messages from a topic with cursor-based pagination. Messages are returned in the specified order.


        **Authorization:** Your API key bot must be a member of the topic to access its messages.


        **Pagination:** Use the `cursor` parameter with the value from `nextCursor` in the response to get the next page.

        The `before` and `after` parameters are mutually exclusive - use one or the other, not both.


        **Note:** For security reasons, a 404 response is returned both when the topic does not exist

        and when your bot is not a member of the topic.

        '
      operationId: getTopicMessages
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - message:read
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: topicId
        in: path
        required: true
        description: The ID of the topic to get messages from
        schema:
          type: string
          format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000
      - name: limit
        in: query
        description: 'Maximum number of messages to return (default: 50, max: 100)'
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 50
      - name: cursor
        in: query
        description: Opaque cursor for pagination. Use the value from `nextCursor` in the response. Cursors are cryptographically signed and validated server-side to prevent tampering.
        required: false
        schema:
          type: string
      - name: before
        in: query
        description: Return messages created before this timestamp (Unix milliseconds). Mutually exclusive with `after`.
        required: false
        schema:
          type: integer
          format: int64
      - name: after
        in: query
        description: Return messages created after this timestamp (Unix milliseconds). Mutually exclusive with `before`.
        required: false
        schema:
          type: integer
          format: int64
      - name: senderId
        in: query
        description: Filter messages by sender ID
        required: false
        schema:
          type: string
      - name: order
        in: query
        description: 'Sort order for messages (default: desc - newest first)'
        required: false
        schema:
          type: string
          enum:
          - asc
          - desc
          default: desc
      - name: includeSystem
        in: query
        description: 'Include system messages (default: true)'
        required: false
        schema:
          type: boolean
          default: true
      - name: threadId
        in: query
        description: Filter to messages within a specific thread (replies to a parent message)
        required: false
        schema:
          type: string
          format: uuid
      - name: includeReactionUsers
        in: query
        description: 'Include user IDs in reaction data (default: false, heavier payload)'
        required: false
        schema:
          type: boolean
          default: false
      responses:
        '200':
          description: Messages retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicMessagesResponse'
              example:
                messages:
                - id: 660e8400-e29b-41d4-a716-446655440001
                  topicId: 550e8400-e29b-41d4-a716-446655440000
                  senderId: 550e8400-e29b-41d4-a716-446655440001
                  senderName: Alice Johnson
                  senderType: user
                  text: Hello team!
                  createdAt: 1699564800000
                  updatedAt: 1699564800000
                  isEdited: false
                  isSystem: false
                  attachments: []
                  mentions: []
                  reactions: []
                - id: 660e8400-e29b-41d4-a716-446655440002
                  topicId: 550e8400-e29b-41d4-a716-446655440000
                  senderId: b@660e8400-e29b-41d4-a716-446655440003
                  senderName: API Bot
                  senderType: bot
                  text: Task created successfully
                  createdAt: 1699564700000
                  updatedAt: 1699564700000
                  isEdited: false
                  isSystem: false
                  attachments: []
                  mentions: []
                  reactions: []
                nextCursor: eyJ0IjoxNjk5NTY0NzAwMDAwLCJpZCI6IjY2MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMiIsIm8iOiJkZXNjIn0=
                hasMore: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/topics/{topicId}/members:
    post:
      summary: Add members to a topic
      description: 'Add one or more members to an existing topic.


        **Authorization:** Your API key bot must be a member of the topic (returns 404 if not).


        **Validation:**

        - All members being added must exist and be from the same organization as the bot (returns 400 "Invalid member" if not)

        - Members already in the topic will result in a 400 error


        **Limits:** Maximum 5 members per request. Duplicate member IDs in the request are automatically removed. For adding many members, create the topic with all members upfront.

        '
      operationId: addTopicMembers
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:write
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: topicId
        in: path
        required: true
        description: The ID of the topic to add members to
        schema:
          type: string
          format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopicMemberAddRequest'
            examples:
              single:
                summary: Add a single member
                value:
                  memberIds:
                  - 550e8400-e29b-41d4-a716-446655440003
              multiple:
                summary: Add multiple members
                value:
                  memberIds:
                  - 550e8400-e29b-41d4-a716-446655440003
                  - 550e8400-e29b-41d4-a716-446655440004
                  - 550e8400-e29b-41d4-a716-446655440005
      responses:
        '200':
          description: Members added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicMemberUpdateResponse'
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                memberIds:
                - 550e8400-e29b-41d4-a716-446655440001
                - 550e8400-e29b-41d4-a716-446655440002
                - 550e8400-e29b-41d4-a716-446655440003
                - b@660e8400-e29b-41d4-a716-446655440003
                updatedAt: 1699564800000
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      summary: Remove members from a topic
      description: 'Remove one or more members from an existing topic.


        **Authorization:** Your API key bot must be a member of the topic (returns 404 if not).


        **Behavior:** Members not currently in the topic are silently ignored. If none of the provided members are in the topic, no removal occurs and the current topic state is returned.


        **Limits:** Maximum 5 members per request. Duplicate member IDs are automatically removed.


        **Note:** The bot can remove itself from the topic if needed.

        '
      operationId: removeTopicMembers
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - channel:write
      tags:
      - Topics (group chats/channels/conversations)
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: topicId
        in: path
        required: true
        description: The ID of the topic to remove members from
        schema:
          type: string
          format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopicMemberRemoveRequest'
            examples:
              single:
                summary: Remove a single member
                value:
                  memberIds:
                  - 550e8400-e29b-41d4-a716-446655440003
              multiple:
                summary: Remove multiple members
                value:
                  memberIds:
                  - 550e8400-e29b-41d4-a716-446655440003
                  - 550e8400-e29b-41d4-a716-446655440004
      responses:
        '200':
          description: Members removed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicMemberUpdateResponse'
              example:
                id: 550e8400-e29b-41d4-a716-446655440000
                memberIds:
                - 550e8400-e29b-41d4-a716-446655440001
                - b@660e8400-e29b-41d4-a716-446655440003
                updatedAt: 1699564800000
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    TopicMemberAddRequest:
      type: object
      required:
      - memberIds
      properties:
        memberIds:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          maxItems: 5
          description: Array of member IDs to add to the topic (max 5). All members must be from the same organization as the bot and must not already be members of the topic. Duplicate IDs in the request are automatically removed.
          example:
          - 550e8400-e29b-41d4-a716-446655440003
          - 550e8400-e29b-41d4-a716-446655440004
    MessageReaction:
      type: object
      properties:
        emoji:
          type: string
          description: The emoji used for the reaction
          example: 👍
        count:
          type: integer
          description: Number of users who reacted with this emoji
          example: 3
        userIds:
          type: array
          items:
            type: string
          description: IDs of users who reacted (if includeReactionUsers is true)
          example:
          - 550e8400-e29b-41d4-a716-446655440001
    TopicListItem:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The topic ID
          example: 550e8400-e29b-41d4-a716-446655440000
        name:
          type: string
          description: The topic name (for DMs, this is the other participant's name)
          example: Project Updates
        description:
          type: string
          description: The topic description (empty for DMs)
          example: Discussion for project milestones
        type:
          type: string
          enum:
          - topic
          - dm
          description: 'The type of conversation:

            - `topic`: A group chat/channel with multiple members

            - `dm`: A direct message conversation between two members

            '
          example: topic
        properties:
          type: array
          items:
            type: string
            enum:
            - announcement
          description: 'Topic properties/flags:

            - `announcement`: An announcement channel (read-only for non-admins)

            '
          example: []
        members:
          type: array
          items:
            type: string
          description: Array of member IDs in the topic
          example:
          - 550e8400-e29b-41d4-a716-446655440001
          - 550e8400-e29b-41d4-a716-446655440002
        createdAt:
          type: integer
          format: int64
          description: Unix timestamp in milliseconds when the topic was created
          example: 1699564800000
        updatedAt:
          type: integer
          format: int64
          description: Unix timestamp in milliseconds when the topic was last updated
          example: 1699564800000
        externalId:
          type: string
          description: Optional external identifier if set when creating the topic
          example: project-alpha
    MessageMention:
      type: object
      properties:
        id:
          type: string
          description: The mentioned profile ID
          example: 550e8400

# --- truncated at 32 KB (45 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/zenzap/refs/heads/main/openapi/zenzap-topics-group-chats-channels-conversations-api-openapi.yml