ZenZap Polls API

Operations for creating polls, recording votes, and retracting votes. Polls are posted as messages in a topic. When you create a poll, each option is assigned a server-generated 6-character ID — use those IDs as `optionId` when submitting votes. **Voting constraints:** - The bot must be a member of the topic the poll was posted in - Anonymous polls (`anonymous: true`) do not support voting via the API - Votes cannot be cast on closed or expired polls - Each `{pollId, optionId, voter}` combination is idempotent - Votes can be retracted with `DELETE /v2/polls/{pollId}/votes/{voteId}` using the `id` returned when the vote was cast

Operations 3

POST /v2/polls Create a poll #
POST /v2/polls/{pollId}/votes Vote on a poll #
DELETE /v2/polls/{pollId}/votes/{voteId} Delete a poll vote #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/zenzap-polls-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

zenzap-polls-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Zenzap External Integration Polls API
  description: API for external applications to integrate with Zenzap.
  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: Polls
  description: Operations for creating polls, recording votes, and retracting votes.
paths:
  /v2/polls:
    post:
      summary: Create a poll
      description: 'Create a poll in a topic. The bot must be a member of the topic.


        Polls are sent as messages. Each option text is stored server-side with a

        server-generated 6-character ID — use those IDs when submitting votes.


        **Anonymous polls** (`anonymous: true`) do not support voting via the API.'
      operationId: createPoll
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - poll:write
      tags:
      - Polls
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PollCreateRequest'
            example:
              topicId: 550e8400-e29b-41d4-a716-446655440000
              question: Which release should we prioritize?
              options:
              - Bug fixes
              - New features
              - Performance improvements
              selectionType: single
      responses:
        '201':
          description: Poll created successfully. The `id` field is the poll ID — use it as `{pollId}` when calling `POST /v2/polls/{pollId}/votes`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PollCreateResponse'
              example:
                id: 770e8400-e29b-41d4-a716-446655440099
                topicId: 550e8400-e29b-41d4-a716-446655440000
                question: Which release should we prioritize?
                options:
                - id: a1b2c3
                  text: Bug fixes
                - id: d4e5f6
                  text: New features
                - id: g7h8i9
                  text: Performance improvements
                selectionType: single
                status: active
                createdAt: 1699564800000
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              examples:
                topicIdRequired:
                  summary: Missing topicId
                  value:
                    message: topicId is required
                questionRequired:
                  summary: Missing question
                  value:
                    message: question is required
                questionTooLong:
                  summary: Question too long
                  value:
                    message: question too long
                invalidSelectionType:
                  summary: Invalid selectionType
                  value:
                    message: selectionType must be "single" or "multiple"
                tooFewOptions:
                  summary: Too few options
                  value:
                    message: at least 2 options are required
                tooManyOptions:
                  summary: Too many options
                  value:
                    message: too many options
                emptyOption:
                  summary: Empty option text
                  value:
                    message: option text cannot be empty
                optionTooLong:
                  summary: Option text too long
                  value:
                    message: option text too long
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Bot is not a member of the topic
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: active profile is not a member of topic
        '404':
          description: Topic not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: topic not found
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/polls/{pollId}/votes:
    post:
      summary: Vote on a poll
      description: 'Submit a vote on a poll on behalf of the bot. The bot must be a member of the topic the poll was posted in.


        Use the `id` values from the `options` array in the `POST /v2/polls` response as the `optionId`.


        **Constraints:**

        - Anonymous polls do not support voting via the API

        - Votes cannot be cast on closed or expired polls

        - Each `{pollId, optionId, voter}` combination is idempotent — re-submitting the same vote is a no-op'
      operationId: createPollVote
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - poll:write
      tags:
      - Polls
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: pollId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The poll ID (returned as `id` in the create poll response)
        example: 770e8400-e29b-41d4-a716-446655440099
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PollVoteCreateRequest'
            example:
              optionId: a1b2c3
      responses:
        '201':
          description: Vote recorded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PollVoteCreateResponse'
              example:
                id: 770e8400-e29b-41d4-a716-446655440099_a1b2c3_b@f951b968-bf80-4ee6-bbbe-6ca338f57fc6
                attachmentId: 770e8400-e29b-41d4-a716-446655440099
                optionId: a1b2c3
                createdAt: 1699564800000
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              examples:
                invalidAttachmentId:
                  summary: Invalid attachment ID format
                  value:
                    message: invalid attachmentId
                invalidOptionId:
                  summary: Invalid option ID
                  value:
                    message: optionId must be non-empty and at most 6 characters
                notAPoll:
                  summary: Attachment is not a poll
                  value:
                    message: attachment is not a poll
                anonymousPoll:
                  summary: Anonymous poll — voting not supported
                  value:
                    message: anonymous polls are not supported
                pollClosed:
                  summary: Poll is closed
                  value:
                    message: poll is closed
                pollExpired:
                  summary: Poll has expired
                  value:
                    message: poll has expired
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Bot is not a member of the topic
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: active profile is not a member of topic
        '404':
          description: Poll not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: poll not found
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/polls/{pollId}/votes/{voteId}:
    delete:
      summary: Delete a poll vote
      description: Retract a previously cast vote on a poll. Provide the poll ID and the vote ID returned when the vote was cast.
      operationId: deletePollVote
      security:
      - bearerAuth: []
        hmacSignature: []
      - oauth2ClientCredentials:
        - poll:write
      tags:
      - Polls
      parameters:
      - $ref: '#/components/parameters/XSignature'
      - $ref: '#/components/parameters/XTimestamp'
      - name: pollId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The poll ID (returned as `id` in the create poll response)
        example: 770e8400-e29b-41d4-a716-446655440099
      - name: voteId
        in: path
        required: true
        schema:
          type: string
        description: The vote ID (returned as `id` in the create vote response)
        example: 770e8400-e29b-41d4-a716-446655440099_a1b2c3_b@f951b968-bf80-4ee6-bbbe-6ca338f57fc6
      responses:
        '204':
          description: Vote deleted successfully
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Vote not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
              example:
                message: vote not found
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    PollCreateResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The poll ID. Use this as the `pollId` path parameter when voting.
          example: 770e8400-e29b-41d4-a716-446655440099
        topicId:
          type: string
          format: uuid
          description: ID of the topic the poll was posted in.
          example: 550e8400-e29b-41d4-a716-446655440000
        question:
          type: string
          description: The poll question.
          example: Which release should we prioritize?
        options:
          type: array
          description: Poll options with their server-generated IDs.
          items:
            $ref: '#/components/schemas/PollOption'
        selectionType:
          type: string
          enum:
          - single
          - multiple
          example: single
        status:
          type: string
          enum:
          - active
          - closed
          description: Current poll status.
          example: active
        anonymous:
          type: boolean
          description: Whether the poll is anonymous.
          example: false
        createdAt:
          type: integer
          format: int64
          description: Creation timestamp in milliseconds.
          example: 1699564800000
    PollOption:
      type: object
      properties:
        id:
          type: string
          description: Server-generated 6-character option ID. Use this as `optionId` when voting.
          example: a1b2c3
        text:
          type: string
          description: Display text for this option.
          example: Bug fixes
    PollVoteCreateResponse:
      type: object
      properties:
        id:
          type: string
          description: Unique vote ID (composite of attachmentId, optionId, and voter profile ID).
          example: 770e8400-e29b-41d4-a716-446655440099_a1b2c3_b@f951b968-bf80-4ee6-bbbe-6ca338f57fc6
        attachmentId:
          type: string
          format: uuid
          description: The poll's attachment ID.
          example: 770e8400-e29b-41d4-a716-446655440099
        optionId:
          type: string
          description: The option that was voted for.
          example: a1b2c3
        createdAt:
          type: integer
          format: int64
          description: Vote creation timestamp in milliseconds.
          example: 1699564800000
    PollVoteCreateRequest:
      type: object
      required:
      - optionId
      properties:
        optionId:
          type: string
          maxLength: 6
          description: The ID of the option to vote for. Use the `id` values from the `options` array in the create poll response.
          example: a1b2c3
    PollCreateRequest:
      type: object
      required:
      - topicId
      - question
      - options
      - selectionType
      properties:
        topicId:
          type: string
          format: uuid
          description: ID of the topic to post the poll in. The bot must be a member.
          example: 550e8400-e29b-41d4-a716-446655440000
        question:
          type: string
          maxLength: 500
          description: The poll question / title.
          example: Which release should we prioritize?
        options:
          type: array
          minItems: 2
          maxItems: 10
          description: Poll answer options. Each item is the display text; IDs are generated server-side.
          items:
            type: string
            maxLength: 1000
          example:
          - Bug fixes
          - New features
          - Performance improvements
        selectionType:
          type: string
          enum:
          - single
          - multiple
          description: 'Whether voters may select one or multiple options:

            - `single`: one choice allowed

            - `multiple`: any number of choices allowed

            '
          example: single
        anonymous:
          type: boolean
          description: 'If `true`, voter identities are hidden. Anonymous polls do **not** support voting via the API.

            '
          example: false
  parameters:
    XSignature:
      name: X-Signature
      in: header
      required: false
      description: "HMAC signature of the request for authentication and replay protection.\n\n**Required only when authenticating with a static API key.** If you are using an OAuth access token (issued by `POST /oauth/token`), omit this header — the JWT carries all the authentication and integrity guarantees.\n\n**Replay Protection:** The signature includes a timestamp to prevent replay attacks.\nRequests with timestamps older than 5 minutes are rejected.\n\nThe signature payload differs by HTTP method:\n- **POST/PUT/PATCH/DELETE**: HMAC-SHA256 of `{timestamp}.{body}`\n- **GET**: HMAC-SHA256 of `{timestamp}.{uri}`\n\nThe signature is calculated as:\n1. Get the current Unix timestamp in milliseconds\n2. Determine the payload:\n   - For POST/PUT/PATCH/DELETE: Use `{timestamp}.{body}` where body is the request body\n   - For GET: Use `{timestamp}.{uri}` where uri is the full request URI (e.g., `/v2/members?limit=10`)\n3. Calculate HMAC-SHA256 of the combined payload using your API secret\n4. Hex-encode the output\n5. Include the timestamp in the `X-Timestamp` header\n\nExample for GET request to `/v2/members?limit=10`:\n```\ntimestamp = 1699564800000\npayload = \"1699564800000./v2/members?limit=10\"\nsignature = HMAC-SHA256(secret, payload)\nX-Signature: hex(signature)\nX-Timestamp: 1699564800000\n```\n\nExample for POST request with body `{\"topicId\":\"123\",\"text\":\"Hello\"}`:\n```\ntimestamp = 1699564800000\npayload = '1699564800000.{\"topicId\":\"123\",\"text\":\"Hello\"}'\nsignature = HMAC-SHA256(secret, payload)\nX-Signature: hex(signature)\nX-Timestamp: 1699564800000\n```\n\nFor `multipart/form-data` requests, sign the exact raw request body bytes\n(including boundaries and file bytes) as transmitted.\n"
      schema:
        type: string
        pattern: ^[a-f0-9]{64}$
        example: a3d5f8e7c2b1d4f6a8e9c7b5d3f1a2e4b6c8d0f2e4a6b8c0d2e4f6a8b0c2d4e6
    XTimestamp:
      name: X-Timestamp
      in: header
      required: false
      description: 'Unix timestamp in milliseconds when the request was created.

        Used for replay protection — requests older than 5 minutes are rejected.


        **Required only when authenticating with a static API key.** Omit when using an OAuth access token.

        '
      schema:
        type: integer
        format: int64
        example: 1699564800000
  responses:
    InternalServerError:
      description: Internal server error
      content:
        text/plain:
          schema:
            type: string
          example: internal server error
    Unauthorized:
      description: Unauthorized - invalid or missing API token
      content:
        text/plain:
          schema:
            type: string
          example: unauthorized
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Bearer token for the request. Two flavors:


        - **Static API key** — pass your API key (the value returned as `apiKey` when the bot was created). Must be paired with `X-Signature` + `X-Timestamp` (the `hmacSignature` scheme).

        - **OAuth access token** — pass the JWT returned by `POST /oauth/token`. No signature headers are required.

        '
    hmacSignature:
      type: apiKey
      in: header
      name: X-Signature
      description: 'HMAC-SHA256 signature for request verification. Required **only** when authenticating with a static API key. Omit when using an OAuth access token.

        '
    oauth2ClientCredentials:
      type: oauth2
      description: 'OAuth 2.0 `client_credentials` grant for API-key bots. Use the `clientId` and `clientSecret` returned when the bot was created (or rotated) to mint short-lived access tokens. See [Authentication](/api-reference/authentication) for details.


        Access tokens are bearer JWTs and expire after 1 hour. There is no refresh token — re-mint with the client credentials when the token expires.

        '
      flows:
        clientCredentials:
          tokenUrl: https://api.zenzap.co/oauth/token
          scopes:
            channel:list: List topics the bot belongs to
            channel:read: Read topic metadata
            channel:write: Create/update topics and manage members
            message:read: Read messages
            message:send: Send messages
            message:write: Edit / delete / mark-delivered / mark-read messages
            reaction:write: Add and remove reactions on messages
            task:read: Read tasks
            task:write: Create / update / delete tasks
            poll:write: Create polls and cast / retract votes
            member:read: List organization members
            updates:read: Long-poll for outbound events