> ## Documentation Index
> Fetch the complete documentation index at: https://developer.dizplai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a poll

> Gets a poll with its question, options and results, to draw it and keep it up to date.



## OpenAPI

````yaml /experiences/api-reference/experiences.openapi.yaml get /polls/{poll_id}
openapi: 3.1.0
info:
  title: 'Dizplai API: Experiences'
  version: 1.0.0
  summary: Read polls, Fan Voices and collections, and let fans vote and send messages.
  description: >
    Show polls and Fan Voices in your own apps and sites, and let fans take
    part: read experiences and collections, send

    fans' votes and messages, and read back a fan's own vote and messages.


    **Headers.** Send `x-api-key`, your organisation's API key, on every
    request. When a fan takes part, or reads

    their own vote or messages, add their token from your own login as
    `Authorization: Bearer <token>`.


    **Names.** An experience is one thing fans take part in: a poll or a Fan
    Voice. A collection groups experiences for a

    match or show, and an experience can be in many collections. Every ID is a
    UUID: store it in a UUID column or as

    text, and never parse it.


    **Conventions.** snake_case fields; `after` and `limit` paging (50 by
    default, 100 at most) with `{items, next}`;

    errors are RFC 9457 problems with a stable `code` and a `request_id`, and
    every response carries `x-request-id`.

    Types, statuses and codes can gain values within v1, so ignore one you don't
    know.


    **Refreshing.** Read an open poll every 10 seconds and lists every 30
    seconds, and wait as long as `Retry-After`

    says after a `429` or `503`. The Experiences guide has the details.
  contact:
    name: Dizplai
servers:
  - url: https://api.dizplai.com/v1
    description: The Dizplai API.
security:
  - apiKey: []
tags:
  - name: Experiences
    description: >-
      Everything fans can take part in, in one list: build a match or show
      screen from it, drawing each experience by its type.
  - name: Collections
    description: >-
      Groups of experiences, one for each match or show, to organise your
      screens. An experience can be in many collections, in its own order in
      each.
  - name: Polls
    description: >-
      A poll asks fans one question with a short list of answers. Read polls and
      their results, send a fan's vote, and read back the vote they made.
  - name: Fan Voices
    description: >-
      A Fan Voice asks fans to reply in their own words, with text, a voice note
      or a photo. Read a Fan Voice, send a fan's message, and show the fan what
      happened to it. Fans never see each other's messages.
paths:
  /polls/{poll_id}:
    parameters:
      - name: poll_id
        in: path
        required: true
        description: The poll's ID, from a list of experiences or polls.
        schema:
          $ref: '#/components/schemas/PollId'
    get:
      tags:
        - Polls
      summary: Get a poll
      description: >-
        Gets a poll with its question, options and results, to draw it and keep
        it up to date.
      operationId: getPoll
      responses:
        '200':
          description: >-
            The poll. results.state says what to show now, and
            results_visibility when fans may see results. While the poll is
            open, read it every 10 seconds. After a vote, show the vote's
            snapshot first: a read straight after the vote may not include it
            yet.
          headers:
            x-request-id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Poll'
              examples:
                live:
                  $ref: '#/components/examples/Poll'
                withheld:
                  $ref: '#/components/examples/PollWithheld'
                final:
                  $ref: '#/components/examples/PollFinal'
        '401':
          $ref: '#/components/responses/Unauthorised'
        '403':
          $ref: '#/components/responses/ReadForbidden'
        '404':
          $ref: '#/components/responses/PollNotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/ReadUnavailable'
components:
  schemas:
    PollId:
      type: string
      description: A poll's ID, a UUID.
      format: uuid
      examples:
        - 0192fa7b-8d41-7bbc-9b58-02311fc6ef8e
    Poll:
      title: Poll
      type: object
      description: >-
        A poll: one question, its options, and the results when fans may see
        them. Show the question with one choice for each option, and send the
        chosen option's id as the fan's vote.
      required:
        - id
        - type
        - status
        - starts_at
        - ends_at
        - metadata
        - locale
        - created_at
        - updated_at
        - results_visibility
        - results
        - requires_sign_in
        - question
        - options
      properties:
        id:
          $ref: '#/components/schemas/PollId'
        type:
          type: string
          enum:
            - poll
          description: Tells polls apart from other experiences in a list.
        status:
          $ref: '#/components/schemas/Status'
        starts_at:
          type:
            - string
            - 'null'
          format: date-time
          description: When it's due to open. Null if your producers open it by hand.
        ends_at:
          type:
            - string
            - 'null'
          format: date-time
          description: When it's due to close. Null if no closing time is set.
        metadata:
          $ref: '#/components/schemas/Metadata'
        locale:
          $ref: '#/components/schemas/Locale'
          description: The language the experience's text is written in, such as en-GB.
        created_at:
          $ref: '#/components/schemas/Timestamp'
          description: When the poll was created.
        updated_at:
          $ref: '#/components/schemas/Timestamp'
          description: >-
            Changes when anything a fan can see changes, including visible
            results, but not when only withheld results change.
        results_visibility:
          type: string
          x-extensible-enum:
            - live
            - after_vote
            - after_close
            - hidden
          description: >-
            When fans may see results. live: always. after_vote: once they've
            voted, or once voting has stopped; the results are in every read, so
            your app hides them until then. after_close: once voting has
            stopped; until then results are withheld. hidden: never; results are
            always withheld, for on air or your own team only. Results that
            mustn't be seen early use after_close or hidden. More values may be
            added: whatever the value, results.state says what to show now.
        results:
          $ref: '#/components/schemas/PollResults'
        requires_sign_in:
          type: boolean
          description: >-
            True if only signed-in fans may take part: show a guest your sign-in
            prompt instead. A guest's vote or message here answers 403
            (sign_in_required). Voice notes and photos are always for signed-in
            fans.
        question:
          type: string
          minLength: 1
          maxLength: 300
          description: The question fans answer.
        subtitle:
          type: string
          maxLength: 300
          description: Supporting text under the question.
        options:
          type: array
          minItems: 2
          maxItems: 10
          description: >-
            Every option, 2 to 10, in the poll's order. Once the poll has gone
            live, its number of options is fixed: your producers can correct an
            option's label, such as a typo, but can't add or remove options.
          items:
            type: object
            required:
              - id
              - label
            properties:
              id:
                $ref: '#/components/schemas/OptionId'
              label:
                type: string
                description: The answer, as fans see it.
                minLength: 1
                maxLength: 200
    Status:
      type: string
      description: >-
        Whether fans can take part now. scheduled: coming up, and goes live at
        starts_at. live: taking votes or messages. closed: taking part has
        stopped; it can reopen. An experience your producers take down or delete
        drops out of lists, and getting it answers 404. More statuses may be
        added: treat one you don't know as closed to taking part.
      x-extensible-enum:
        - scheduled
        - live
        - closed
    Metadata:
      type: object
      maxProperties: 50
      propertyNames:
        maxLength: 40
      additionalProperties:
        type: string
        maxLength: 500
      description: >-
        Tags for finding and grouping things, such as the match or show they're
        about. Filter lists by them with `metadata[key]=value`. Up to 50 keys of
        up to 40 characters, values up to 500. One key is reserved, event_id,
        set by your producers; every other key is yours, and never interpreted.
      properties:
        event_id:
          type: string
          maxLength: 64
          description: >-
            An ID for the match or show this is about, set by your producers.
            Reserved.
    Locale:
      type: string
      maxLength: 35
      pattern: ^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$
      examples:
        - en-GB
      description: >-
        A BCP 47 language tag. en-GB, British English, is the only language for
        now. More may be added: show text in a locale you don't know as it is.
      x-extensible-enum:
        - en-GB
    Timestamp:
      type: string
      format: date-time
      description: A date and time, RFC 3339, in UTC.
    PollResults:
      description: >-
        What to show for the poll's results, by state. withheld: fans may not
        see them yet, as results_visibility says, and nothing else is sent.
        live: the current counts. final: voting has stopped and these are the
        confirmed totals, which can differ from the last live numbers, and go
        back to live if the poll opens again. Counts are never null: 0 means no
        votes. More states may be added: treat a state you don't know as
        withheld: show no counts.
      type: object
      required:
        - state
      properties:
        state:
          type: string
          x-extensible-enum:
            - withheld
            - live
            - final
          description: >-
            What to show now. Treat a state you don't know as withheld: show no
            counts.
      oneOf:
        - $ref: '#/components/schemas/WithheldResults'
        - title: Counted
          type: object
          required:
            - state
            - total_votes
            - options
          properties:
            state:
              type: string
              enum:
                - live
                - final
              description: >-
                live: the current counts, while votes are open. final: voting
                has stopped and these are the confirmed totals, which can differ
                from the last live numbers. If voting opens again, they go back
                to live.
            total_votes:
              type: integer
              minimum: 0
              description: 'Fans who voted. Never null: 0 means no votes.'
            options:
              type: array
              description: >-
                Every option, in the poll's order. Match option_id to the poll's
                options[].id for its label.
              items:
                type: object
                required:
                  - option_id
                  - votes
                  - percent
                properties:
                  option_id:
                    $ref: '#/components/schemas/OptionId'
                  votes:
                    $ref: '#/components/schemas/Votes'
                  percent:
                    $ref: '#/components/schemas/Percent'
        - title: Another state
          type: object
          required:
            - state
          description: 'A state added later. Treat it as withheld: show no counts.'
          properties:
            state:
              type: string
              not:
                enum:
                  - withheld
                  - live
                  - final
    OptionId:
      type: string
      description: >-
        An option's ID, what a fan's vote sends. Created with the option,
        opaque, and never reused, even if the option is removed before the poll
        goes live. Correcting an option's label keeps its ID.
      format: uuid
      examples:
        - 01a1f97a-b538-778f-bad7-0c1c35ff701c
    Problem:
      type: object
      required:
        - type
        - code
        - title
        - status
        - request_id
      description: >-
        What went wrong, in the same shape for every error: an RFC 9457 problem
        with a stable code. Act on code, which never changes meaning within a
        version, and on the HTTP status for a code you don't know. Quote
        request_id to support.
      properties:
        type:
          type: string
          format: uri-reference
          description: >-
            One URL per code: https://api.dizplai.com/problems/ followed by the
            code with hyphens, such as
            https://api.dizplai.com/problems/unknown-option for unknown_option.
        code:
          type: string
          x-extensible-enum:
            - invalid_request
            - unknown_option
            - not_open
            - media_not_accepted
            - invalid_upload
            - invalid_api_key
            - invalid_fan_token
            - forbidden
            - fan_blocked
            - sign_in_required
            - message_limit_reached
            - not_found
            - idempotency_conflict
            - rate_limited
            - unavailable
          description: >
            More codes may be added: for one you don't know, act on the HTTP
            status.


            | code | Status | Retry? | Meaning |

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

            | invalid_request | 400 | No | The body or a parameter is invalid,
            or a required header such as Idempotency-Key is missing. |

            | unknown_option | 400 | No; read the poll again | An option ID the
            poll doesn't have. |

            | not_open | 400 | No; read the experience again | The experience
            isn't taking votes or messages: it isn't live yet, or votes have
            stopped. |

            | media_not_accepted | 400 | No | The Fan Voice doesn't take this
            kind of message, or the file's type or size is outside the limits. |

            | invalid_upload | 400 | No; upload again | The upload_id is
            unknown, already used or another fan's, or the file was never
            uploaded or its type or size differs from what you asked for. |

            | invalid_api_key | 401 | No | A missing or invalid x-api-key. |

            | invalid_fan_token | 401 | Once, with a fresh token | A missing,
            invalid or expired fan token, or one from another organisation's
            login. It carries WWW-Authenticate. |

            | forbidden | 403 | No | Your API key isn't allowed to make this
            request. |

            | fan_blocked | 403 | No | The fan is blocked from this Fan Voice. |

            | sign_in_required | 403 | No; ask the fan to sign in | A guest on
            an experience that needs a signed-in fan, or a guest's voice note or
            photo. |

            | message_limit_reached | 403 | No | The fan has used up this Fan
            Voice's messages of this kind. |

            | not_found | 404 | No | Not found, or not yours. |

            | idempotency_conflict | 409 | No | An Idempotency-Key reused with a
            different body while it's kept: 24 hours, or 5 minutes for an
            upload. |

            | rate_limited | 429 | After Retry-After | Too many requests. |

            | unavailable | 503 | After Retry-After | Votes or messages can't be
            taken right now. |
        title:
          type: string
          description: A short title for the code, such as Not open. It doesn't change.
        status:
          type: integer
          description: The HTTP status code.
          minimum: 400
          maximum: 599
        detail:
          type: string
          description: >-
            What went wrong, in plain English. It can change, so don't act on
            it.
        request_id:
          type: string
          description: Matches the x-request-id response header.
        errors:
          type: array
          description: Field-level validation errors, with invalid_request.
          items:
            type: object
            required:
              - pointer
              - message
            properties:
              pointer:
                type: string
                description: A JSON Pointer to the field.
              message:
                type: string
                description: What's wrong with that field.
    WithheldResults:
      title: Withheld
      type: object
      required:
        - state
      description: >-
        Results fans may not see yet, as results_visibility says: only the state
        is sent, so show no counts.
      properties:
        state:
          type: string
          enum:
            - withheld
    Votes:
      type: integer
      minimum: 0
      description: 'Votes counted. Never null: 0 means no votes.'
    Percent:
      type: number
      minimum: 0
      maximum: 100
      description: >-
        Of total_votes, 0 to 100, rounded to one decimal place, so they may not
        add up to exactly 100.
  headers:
    RequestId:
      description: The request's ID. Quote it to support.
      schema:
        type: string
    RetryAfter:
      description: >-
        How long to wait before retrying, as a whole number of seconds. Sent
        with every 429 and 503.
      schema:
        type: integer
        minimum: 0
  examples:
    Poll:
      summary: Live
      value:
        id: 0192fa7b-8d41-7bbc-9b58-02311fc6ef8e
        type: poll
        status: live
        starts_at: null
        ends_at: null
        metadata:
          event_id: ev_2041
        locale: en-GB
        created_at: '2026-11-20T15:02:11Z'
        updated_at: '2026-11-21T20:41:07Z'
        results_visibility: after_vote
        requires_sign_in: false
        question: Who was your player of the match?
        options:
          - id: 01a1f97a-b538-778f-bad7-0c1c35ff701c
            label: Jordan Mensah
          - id: 01a1f97a-b5a7-7b5b-9458-203a658c1e8d
            label: Kai Brennan
          - id: 01a1f97a-b5cc-7fcf-989c-56ebe53808c5
            label: Amara Osei
        results:
          state: live
          total_votes: 4210
          options:
            - option_id: 01a1f97a-b538-778f-bad7-0c1c35ff701c
              votes: 2105
              percent: 50
            - option_id: 01a1f97a-b5a7-7b5b-9458-203a658c1e8d
              votes: 1263
              percent: 30
            - option_id: 01a1f97a-b5cc-7fcf-989c-56ebe53808c5
              votes: 842
              percent: 20
    PollWithheld:
      summary: Results withheld until votes stop
      value:
        id: 0192fa7b-8d41-7bbc-9b58-02311fc6ef8e
        type: poll
        status: live
        starts_at: null
        ends_at: null
        metadata:
          event_id: ev_2041
        locale: en-GB
        created_at: '2026-11-20T15:02:11Z'
        updated_at: '2026-11-21T20:41:07Z'
        results_visibility: after_close
        requires_sign_in: false
        question: Who was your player of the match?
        options:
          - id: 01a1f97a-b538-778f-bad7-0c1c35ff701c
            label: Jordan Mensah
          - id: 01a1f97a-b5a7-7b5b-9458-203a658c1e8d
            label: Kai Brennan
          - id: 01a1f97a-b5cc-7fcf-989c-56ebe53808c5
            label: Amara Osei
        results:
          state: withheld
    PollFinal:
      summary: Closed, with its final results
      value:
        id: 0192fa7b-8d41-7bbc-9b58-02311fc6ef8e
        type: poll
        status: closed
        starts_at: null
        ends_at: '2026-11-21T21:40:00Z'
        metadata:
          event_id: ev_2041
        locale: en-GB
        created_at: '2026-11-20T15:02:11Z'
        updated_at: '2026-11-21T21:40:03Z'
        results_visibility: after_vote
        requires_sign_in: false
        question: Who was your player of the match?
        options:
          - id: 01a1f97a-b538-778f-bad7-0c1c35ff701c
            label: Jordan Mensah
          - id: 01a1f97a-b5a7-7b5b-9458-203a658c1e8d
            label: Kai Brennan
          - id: 01a1f97a-b5cc-7fcf-989c-56ebe53808c5
            label: Amara Osei
        results:
          state: final
          total_votes: 5000
          options:
            - option_id: 01a1f97a-b538-778f-bad7-0c1c35ff701c
              votes: 2412
              percent: 48.2
            - option_id: 01a1f97a-b5a7-7b5b-9458-203a658c1e8d
              votes: 1588
              percent: 31.8
            - option_id: 01a1f97a-b5cc-7fcf-989c-56ebe53808c5
              votes: 1000
              percent: 20
  responses:
    Unauthorised:
      description: >-
        A missing or invalid x-api-key (invalid_api_key). Don't retry: check the
        key.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            invalid_api_key:
              summary: invalid_api_key
              value:
                type: https://api.dizplai.com/problems/invalid-api-key
                code: invalid_api_key
                title: Invalid API key
                status: 401
                detail: The x-api-key isn't recognised.
                request_id: 01JBX8P2R4T6V8X0Z2B4D6F8H0
    ReadForbidden:
      description: >-
        Not allowed for this caller or origin (forbidden), such as a browser
        Origin your organisation hasn't registered, or a platform key sent from
        a browser. Retrying won't help: check the key and your registered
        origins.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            forbidden:
              summary: forbidden
              value:
                type: https://api.dizplai.com/problems/forbidden
                code: forbidden
                title: Forbidden
                status: 403
                detail: This origin isn't registered for this organisation.
                request_id: 01JBX8P2R4T6V8X0Z2B4D6F8H0
    PollNotFound:
      description: >-
        The poll doesn't exist, isn't yours, or was taken down or deleted
        (not_found).
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            not_found:
              summary: not_found
              value:
                type: https://api.dizplai.com/problems/not-found
                code: not_found
                title: Not found
                status: 404
                detail: No such poll.
                request_id: 01JBX8P2R4T6V8X0Z2B4D6F8H0
    TooManyRequests:
      description: >-
        Too many requests (rate_limited). Wait the number of seconds in
        Retry-After, then retry.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            rate_limited:
              summary: rate_limited
              value:
                type: https://api.dizplai.com/problems/rate-limited
                code: rate_limited
                title: Rate limited
                status: 429
                detail: Too many requests. Retry after 2 seconds.
                request_id: 01JBX8P2R4T6V8X0Z2B4D6F8H0
    ReadUnavailable:
      description: >-
        This can't be read right now (unavailable). Wait the number of seconds
        in Retry-After, then retry, and keep showing what you last read.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            unavailable:
              summary: unavailable
              value:
                type: https://api.dizplai.com/problems/unavailable
                code: unavailable
                title: Unavailable
                status: 503
                detail: This can't be read right now. Retry after 5 seconds.
                request_id: 01JBX8P2R4T6V8X0Z2B4D6F8H0
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Your organisation's API key, supplied by Dizplai. Send it on every
        request. It isn't a secret, so it can ship in your app: what a fan does
        is protected by the fan's token.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.