{
  "openapi": "3.1.0",
  "info": {
    "title": "Polls API",
    "version": "1.0.0",
    "summary": "Free live polls and audience Q&A for meetings, classes and talks, a free alternative to Slido and Mentimeter.",
    "description": "Create an event with its polls in one call, hand people the 6-digit code or the audience link, and read the results afterwards. No account and no API key: creating an event returns an owner key, which the results routes need in the x-owner-key header (or as ?key=). The owner key, adminUrl and presentUrl read every answer, so keep them private. People vote in the browser, one vote per device per poll; this API does not vote. Errors are JSON with an error sentence that says what to change. Free with no limits. Full guide: https://polls-free.openapps.xyz/llms.txt",
    "contact": {
      "name": "OpenApps",
      "url": "https://free-apps.openapps.xyz/"
    }
  },
  "servers": [
    {
      "url": "https://functions.bounded.sh/apps/334801de44cb0fe911d5a88b/api"
    }
  ],
  "externalDocs": {
    "description": "llms.txt",
    "url": "https://polls-free.openapps.xyz/llms.txt"
  },
  "paths": {
    "/": {
      "get": {
        "operationId": "describe",
        "summary": "Describe the API and its routes",
        "responses": {
          "200": {
            "description": "Name, docs links, poll types and routes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "about": {
                      "type": "string"
                    },
                    "docs": {
                      "type": "string"
                    },
                    "openapi": {
                      "type": "string"
                    },
                    "pollTypes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PollType"
                      }
                    },
                    "routes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": {
                  "name": "Polls by OpenApps",
                  "about": "Free live polls and audience Q&A for meetings, classes and talks. No account and no caps. Creating an event returns a 6-digit join code, the audience link, and an owner key: keep the key to read results.",
                  "docs": "https://polls-free.openapps.xyz/llms.txt",
                  "openapi": "https://polls-free.openapps.xyz/openapi.json",
                  "pollTypes": [
                    "choice",
                    "wordcloud",
                    "rating",
                    "open",
                    "ranking"
                  ],
                  "routes": [
                    "POST /events {title, polls: [{type, question, options?, multi?, scale?, words?, open?}], qa?, moderate?, allowChange?} -> eventId, code, joinUrl, adminUrl, presentUrl, ownerKey",
                    "GET /events/:id -> the event as the audience sees it: title, code, open and closed polls",
                    "POST /events/:id/questions {text, name?, id?} -> asks the speaker a question; it waits for approval if the host moderates",
                    "GET /events/:id/results?format=json|csv (header x-owner-key) -> every poll's results and the Q&A",
                    "GET /events/:id/questions?format=json|csv (header x-owner-key) -> every audience question, most upvoted first"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "post": {
        "operationId": "createEvent",
        "summary": "Create an event with its polls (no key needed)",
        "description": "Returns the 6-digit join code and the audience link to share, the admin and present links for the host, and the owner key for the results routes. Polls start as drafts the audience cannot see; add \"open\": true to a poll to open it for voting right away. Up to 95 polls per call; the host can add more from adminUrl.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEvent"
              },
              "example": {
                "title": "Team retro",
                "polls": [
                  {
                    "type": "wordcloud",
                    "question": "One word for this sprint?",
                    "words": 3
                  },
                  {
                    "type": "choice",
                    "question": "What should we fix first?",
                    "options": [
                      "Flaky tests",
                      "Slow deploys",
                      "Meetings"
                    ],
                    "multi": true
                  },
                  {
                    "type": "rating",
                    "question": "How was the sprint?",
                    "scale": 5
                  },
                  {
                    "type": "open",
                    "question": "Anything else?"
                  },
                  {
                    "type": "ranking",
                    "question": "Order these by priority",
                    "options": [
                      "Docs",
                      "Speed",
                      "Design"
                    ]
                  }
                ],
                "qa": true,
                "moderate": false,
                "allowChange": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventCreated"
                },
                "example": {
                  "eventId": "k3XqP9mT2vRzW8LwN4hY",
                  "code": "482913",
                  "joinUrl": "https://polls-free.openapps.xyz/e/k3XqP9mT2vRzW8LwN4hY",
                  "joinAt": "Go to polls-free.openapps.xyz and enter 482 913",
                  "adminUrl": "https://polls-free.openapps.xyz/e/k3XqP9mT2vRzW8LwN4hY/admin#k=Qm7tR2xV9pL4nK8sW3zH6jYc",
                  "presentUrl": "https://polls-free.openapps.xyz/e/k3XqP9mT2vRzW8LwN4hY/present#k=Qm7tR2xV9pL4nK8sW3zH6jYc",
                  "ownerKey": "Qm7tR2xV9pL4nK8sW3zH6jYc",
                  "title": "Team retro",
                  "polls": [
                    {
                      "id": "PCxo5myN8ab7",
                      "type": "wordcloud",
                      "question": "One word for this sprint?",
                      "status": "draft",
                      "position": 1
                    },
                    {
                      "id": "Vppv6iNZRqPn",
                      "type": "choice",
                      "question": "What should we fix first?",
                      "status": "draft",
                      "position": 2
                    }
                  ],
                  "note": "Show the audience the code or joinUrl. Keep ownerKey, adminUrl and presentUrl private: they run the event and read every answer. Open presentUrl on the screen you share; arrow keys move between polls and R shows results."
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, or a title or poll does not fit (the error says which, for example \"Poll 2 needs at least two options.\" or \"One call can add up to 95 polls.\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}": {
      "get": {
        "operationId": "readEvent",
        "summary": "Read an event as the audience sees it",
        "description": "Title, join code and link, whether Q&A is on, and the open and closed polls with their options. Drafts are left out. No key needed: knowing the event id is enough.",
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "The event id: 20 letters and digits, from POST /events or the joinUrl.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{20}$"
            },
            "example": "k3XqP9mT2vRzW8LwN4hY"
          }
        ],
        "responses": {
          "200": {
            "description": "The event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicEvent"
                },
                "example": {
                  "eventId": "k3XqP9mT2vRzW8LwN4hY",
                  "title": "Team retro",
                  "code": "482913",
                  "joinUrl": "https://polls-free.openapps.xyz/e/k3XqP9mT2vRzW8LwN4hY",
                  "joinAt": "Go to polls-free.openapps.xyz and enter 482 913",
                  "qa": true,
                  "polls": [
                    {
                      "id": "Vppv6iNZRqPn",
                      "type": "choice",
                      "question": "What should we fix first?",
                      "status": "open",
                      "options": [
                        "Flaky tests",
                        "Slow deploys",
                        "Meetings"
                      ],
                      "multi": true
                    },
                    {
                      "id": "LGeUa9gEFAR9",
                      "type": "rating",
                      "question": "How was the sprint?",
                      "status": "closed",
                      "scale": 5
                    }
                  ],
                  "note": "People vote and ask questions in the browser at joinUrl. Results need the owner key: GET /events/:id/results."
                }
              }
            }
          },
          "404": {
            "description": "No event with that id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}/questions": {
      "post": {
        "operationId": "askQuestion",
        "summary": "Ask the speaker a question (no key needed)",
        "description": "Adds an audience question. If the host moderates questions, it waits for approval; otherwise everyone in the event can see and upvote it right away. The web app sends its questions here too, so a question is never stored under the account of the person who asked it. An optional id (16 letters or digits) lets a browser that recorded that id in events/<eventId>/asked/<its user id>/q/<id> see its own question while it waits for approval.",
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "The event id: 20 letters and digits, from POST /events or the joinUrl.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{20}$"
            },
            "example": "k3XqP9mT2vRzW8LwN4hY"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskQuestion"
              },
              "example": {
                "text": "Will the slides be shared?",
                "name": "Dana"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The question was added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionAsked"
                },
                "example": {
                  "id": "h7RkT2mQ9xWvL4pZ",
                  "status": "live",
                  "note": "Everyone in the event can see and upvote it."
                }
              }
            }
          },
          "400": {
            "description": "No text, text over 300 characters, a name over 40 characters, or an id that is not 16 letters or digits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The host turned questions off for this event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No event with that id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A question with that id already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "readQuestions",
        "summary": "Read every audience question, most upvoted first (owner key)",
        "description": "Every question, including ones waiting for approval and hidden ones, with its upvotes and status. ?format=csv returns a CSV file instead.",
        "security": [
          {
            "ownerKey": []
          },
          {
            "ownerKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "The event id: 20 letters and digits, from POST /events or the joinUrl.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{20}$"
            },
            "example": "k3XqP9mT2vRzW8LwN4hY"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "json (the default) or csv.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The questions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Questions"
                },
                "example": {
                  "title": "Team retro",
                  "count": 2,
                  "questions": [
                    {
                      "question": "Will the slides be shared?",
                      "name": "Dana",
                      "upvotes": 4,
                      "status": "live",
                      "statusLabel": "Live",
                      "askedAt": "2026-10-19T13:35:16.000Z"
                    },
                    {
                      "question": "Can we move the retro to Friday?",
                      "name": null,
                      "upvotes": 1,
                      "status": "answered",
                      "statusLabel": "Answered",
                      "askedAt": "2026-10-19T13:36:02.000Z"
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "\"Question\",\"Name\",\"Upvotes\",\"Status\",\"Asked (UTC)\"\r\n\"Will the slides be shared?\",\"Dana\",\"4\",\"Live\",\"2026-10-19 13:35:16\"\r\n"
              }
            }
          },
          "400": {
            "description": "format is not json or csv",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No owner key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The owner key does not match this event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No event with that id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}/results": {
      "get": {
        "operationId": "readResults",
        "summary": "Read every poll's results and the Q&A (owner key)",
        "description": "Each poll with how many people answered and its results: votes per option (choice), average and spread (rating), words with counts (wordcloud), every answer newest first (open), or the group's order (ranking). Plus every audience question. ?format=csv returns the poll results as a CSV file instead.",
        "security": [
          {
            "ownerKey": []
          },
          {
            "ownerKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "The event id: 20 letters and digits, from POST /events or the joinUrl.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{20}$"
            },
            "example": "k3XqP9mT2vRzW8LwN4hY"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "json (the default) or csv.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Results"
                },
                "example": {
                  "eventId": "k3XqP9mT2vRzW8LwN4hY",
                  "title": "Team retro",
                  "code": "482913",
                  "joinUrl": "https://polls-free.openapps.xyz/e/k3XqP9mT2vRzW8LwN4hY",
                  "joinAt": "Go to polls-free.openapps.xyz and enter 482 913",
                  "polls": [
                    {
                      "id": "Vppv6iNZRqPn",
                      "type": "choice",
                      "question": "What should we fix first?",
                      "status": "closed",
                      "options": [
                        "Flaky tests",
                        "Slow deploys",
                        "Meetings"
                      ],
                      "multi": true,
                      "answered": 12,
                      "results": [
                        {
                          "option": "Flaky tests",
                          "votes": 8
                        },
                        {
                          "option": "Slow deploys",
                          "votes": 5
                        },
                        {
                          "option": "Meetings",
                          "votes": 2
                        }
                      ]
                    },
                    {
                      "id": "LGeUa9gEFAR9",
                      "type": "rating",
                      "question": "How was the sprint?",
                      "status": "closed",
                      "scale": 5,
                      "answered": 11,
                      "average": 3.64,
                      "distribution": [
                        {
                          "rating": 1,
                          "votes": 0
                        },
                        {
                          "rating": 2,
                          "votes": 1
                        },
                        {
                          "rating": 3,
                          "votes": 4
                        },
                        {
                          "rating": 4,
                          "votes": 4
                        },
                        {
                          "rating": 5,
                          "votes": 2
                        }
                      ]
                    },
                    {
                      "id": "PCxo5myN8ab7",
                      "type": "wordcloud",
                      "question": "One word for this sprint?",
                      "status": "closed",
                      "wordsPerPerson": 3,
                      "answered": 10,
                      "words": [
                        {
                          "word": "busy",
                          "count": 6
                        },
                        {
                          "word": "fun",
                          "count": 3
                        }
                      ]
                    },
                    {
                      "id": "YRappMu3ACqa",
                      "type": "open",
                      "question": "Anything else?",
                      "status": "closed",
                      "answered": 2,
                      "answers": [
                        "More pairing, please",
                        "Thanks for the snacks"
                      ]
                    },
                    {
                      "id": "8dPioqp9MpAd",
                      "type": "ranking",
                      "question": "Order these by priority",
                      "status": "closed",
                      "options": [
                        "Docs",
                        "Speed",
                        "Design"
                      ],
                      "answered": 9,
                      "ranking": [
                        {
                          "place": 1,
                          "option": "Speed",
                          "averagePosition": 1.44
                        },
                        {
                          "place": 2,
                          "option": "Docs",
                          "averagePosition": 2
                        },
                        {
                          "place": 3,
                          "option": "Design",
                          "averagePosition": 2.56
                        }
                      ]
                    }
                  ],
                  "questions": [
                    {
                      "question": "Will the slides be shared?",
                      "name": "Dana",
                      "upvotes": 4,
                      "status": "live",
                      "statusLabel": "Live",
                      "askedAt": "2026-10-19T13:35:16.000Z"
                    },
                    {
                      "question": "Can we move the retro to Friday?",
                      "name": null,
                      "upvotes": 1,
                      "status": "answered",
                      "statusLabel": "Answered",
                      "askedAt": "2026-10-19T13:36:02.000Z"
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "\"Poll\",\"Question\",\"Type\",\"Answer\",\"Votes\",\"Percent\",\"Average\"\r\n\"1\",\"What should we fix first?\",\"Multiple choice\",\"Flaky tests\",\"8\",\"67%\",\"\"\r\n"
              }
            }
          },
          "400": {
            "description": "format is not json or csv",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No owner key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The owner key does not match this event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No event with that id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ownerKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-owner-key",
        "description": "The event's owner key: 24 letters and digits, from POST /events (ownerKey, or the part after #k= in adminUrl)."
      },
      "ownerKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "The owner key as a query parameter, for tools that cannot send headers."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A sentence for a person that says what to change."
          }
        },
        "example": {
          "error": "That owner key does not match this event."
        }
      },
      "PollType": {
        "type": "string",
        "enum": [
          "choice",
          "wordcloud",
          "rating",
          "open",
          "ranking"
        ],
        "description": "choice: multiple choice. wordcloud: short words. rating: a scale from 1. open: free text. ranking: put options in order. Common names such as multiple_choice, word_cloud, scale and text are accepted too."
      },
      "PollInput": {
        "type": "object",
        "required": [
          "question"
        ],
        "properties": {
          "type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PollType"
              }
            ],
            "default": "choice"
          },
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 120
            },
            "minItems": 2,
            "maxItems": 30,
            "description": "choice and ranking only: 2 to 30 options for choice, 2 to 12 for ranking. Blank and repeated options are dropped."
          },
          "multi": {
            "type": "boolean",
            "default": false,
            "description": "choice only: people can pick several options."
          },
          "scale": {
            "type": "integer",
            "minimum": 3,
            "maximum": 10,
            "default": 5,
            "description": "rating only: the top of the scale."
          },
          "words": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "default": 3,
            "description": "wordcloud only: how many words each person can give (up to 30 characters each)."
          },
          "open": {
            "type": "boolean",
            "default": false,
            "description": "Open the poll for voting right away instead of starting as a draft."
          }
        }
      },
      "CreateEvent": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "polls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PollInput"
            },
            "maxItems": 95
          },
          "qa": {
            "type": "boolean",
            "default": true,
            "description": "Take questions from the audience."
          },
          "moderate": {
            "type": "boolean",
            "default": false,
            "description": "Questions wait for the host's approval."
          },
          "allowChange": {
            "type": "boolean",
            "default": true,
            "description": "People can change an answer while a poll is open."
          }
        }
      },
      "JoinLinks": {
        "type": "object",
        "required": [
          "code",
          "joinUrl",
          "joinAt"
        ],
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^[1-9][0-9]{5}$",
            "description": "The 6-digit join code."
          },
          "joinUrl": {
            "type": "string",
            "format": "uri",
            "description": "The audience link; the QR code on the present screen opens it."
          },
          "joinAt": {
            "type": "string",
            "description": "How to join, in words."
          }
        }
      },
      "EventCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JoinLinks"
          },
          {
            "type": "object",
            "required": [
              "eventId",
              "adminUrl",
              "presentUrl",
              "ownerKey",
              "title",
              "polls",
              "note"
            ],
            "properties": {
              "eventId": {
                "type": "string"
              },
              "adminUrl": {
                "type": "string",
                "format": "uri",
                "description": "The host's page. Carries the owner key. Private."
              },
              "presentUrl": {
                "type": "string",
                "format": "uri",
                "description": "Present mode for the shared screen. Carries the owner key. Private."
              },
              "ownerKey": {
                "type": "string",
                "description": "For the owner routes. Private."
              },
              "title": {
                "type": "string"
              },
              "polls": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "type",
                    "question",
                    "status",
                    "position"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "type": {
                      "$ref": "#/components/schemas/PollType"
                    },
                    "question": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "draft",
                        "open"
                      ]
                    },
                    "position": {
                      "type": "integer",
                      "minimum": 1
                    }
                  }
                }
              },
              "note": {
                "type": "string"
              }
            }
          }
        ]
      },
      "Poll": {
        "type": "object",
        "required": [
          "id",
          "type",
          "question",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/PollType"
          },
          "question": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "open",
              "closed"
            ],
            "description": "Drafts appear only in owner results."
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "choice and ranking polls."
          },
          "multi": {
            "type": "boolean",
            "description": "choice polls."
          },
          "scale": {
            "type": "integer",
            "description": "rating polls."
          },
          "wordsPerPerson": {
            "type": "integer",
            "description": "wordcloud polls."
          }
        }
      },
      "PublicEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JoinLinks"
          },
          {
            "type": "object",
            "required": [
              "eventId",
              "title",
              "qa",
              "polls",
              "note"
            ],
            "properties": {
              "eventId": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "qa": {
                "type": "boolean",
                "description": "Whether the event takes questions."
              },
              "polls": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Poll"
                }
              },
              "note": {
                "type": "string"
              }
            }
          }
        ]
      },
      "PollResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Poll"
          },
          {
            "type": "object",
            "required": [
              "answered"
            ],
            "properties": {
              "answered": {
                "type": "integer",
                "description": "How many people answered."
              },
              "results": {
                "type": "array",
                "description": "choice: votes per option.",
                "items": {
                  "type": "object",
                  "properties": {
                    "option": {
                      "type": "string"
                    },
                    "votes": {
                      "type": "integer"
                    }
                  }
                }
              },
              "average": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "rating: the average, or null before anyone answers."
              },
              "distribution": {
                "type": "array",
                "description": "rating: how many picked each number.",
                "items": {
                  "type": "object",
                  "properties": {
                    "rating": {
                      "type": "integer"
                    },
                    "votes": {
                      "type": "integer"
                    }
                  }
                }
              },
              "words": {
                "type": "array",
                "description": "wordcloud: words with counts, most common first (top 100).",
                "items": {
                  "type": "object",
                  "properties": {
                    "word": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              },
              "answers": {
                "type": "array",
                "description": "open: every answer, newest first.",
                "items": {
                  "type": "string"
                }
              },
              "ranking": {
                "type": "array",
                "description": "ranking: the group's order; averagePosition 1 is best.",
                "items": {
                  "type": "object",
                  "properties": {
                    "place": {
                      "type": "integer"
                    },
                    "option": {
                      "type": "string"
                    },
                    "averagePosition": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Question": {
        "type": "object",
        "required": [
          "question",
          "name",
          "upvotes",
          "status",
          "statusLabel",
          "askedAt"
        ],
        "properties": {
          "question": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "null when the person did not give a name."
          },
          "upvotes": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "live",
              "answered",
              "hidden"
            ]
          },
          "statusLabel": {
            "type": "string"
          },
          "askedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Results": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JoinLinks"
          },
          {
            "type": "object",
            "required": [
              "eventId",
              "title",
              "polls",
              "questions"
            ],
            "properties": {
              "eventId": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "polls": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PollResult"
                }
              },
              "questions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Question"
                }
              }
            }
          }
        ]
      },
      "Questions": {
        "type": "object",
        "required": [
          "title",
          "count",
          "questions"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Question"
            }
          }
        }
      },
      "AskQuestion": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "The question. question is accepted as another name for it."
          },
          "name": {
            "type": "string",
            "maxLength": 40,
            "description": "Leave out to ask without a name."
          },
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{16}$",
            "description": "Optional; a new id is made when left out."
          }
        }
      },
      "QuestionAsked": {
        "type": "object",
        "required": [
          "id",
          "status",
          "note"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "live"
            ]
          },
          "note": {
            "type": "string"
          }
        }
      }
    }
  }
}
