Admin panel

Polls and Quizzes API

You can create and publish polls, quizzes and rating scales via API — full parity with the Widgets → Polls and Quizzes admin panel, so external systems can publish engagement materials automatically.

A poll cluster is the unit you publish: it targets one or more rooms, carries the scheduling, and contains one question (a standalone poll) or several questions in a row (a series). Each poll inside a cluster is a single question with its options.

Required headers for all endpoints

⚠️

Regional endpoints: Replace chatbackend.watchers.io with the endpoint matching your project region. See Supported Regions.

Region Endpoint
Europe (default) chatbackend.watchers.io
North America chatbackend.us.watchers.io
South America chatbackend.sa.watchers.io
Asia chatbackend.hk.watchers.io
Africa chatbackend.za.watchers.io
Parameter Description
x-api-key Your public API key for the project
Authorization Bearer <token> from the admin panel (Settings → Bearer tokens) for back-to-back integrations

Poll types

Type Description
POLL A regular poll — no correct answer. Single or multiple choice (isMultiple).
QUIZ A poll with correct answer(s). Mark correct options with isRight: true.
RATING A rating scale. Set ratingScale (e.g. 3, 5, 10).

To any type you can add a free-text custom answer option (isCustom: true).

Endpoints

POST /external/poll-cluster — create a poll/series

Creates a poll cluster together with its questions and targets it to rooms.

Field Type Required Description
name string No Internal name of the cluster
isStandalone boolean No true for a single question, false (default) for a series
isActive boolean No Default true
roomIds string[] No External room IDs to publish to (JSON array or CSV file)
startTime ISO datetime No Scheduled publish time. If omitted — published immediately
endTime ISO datetime No Auto-finish time
dailyWindowStart HH:MM No Show only after this time each day
dailyWindowEnd HH:MM No Hide after this time each day
polls Poll[] No The questions (see Poll object)

GET /external/poll-cluster — list

Query parameters: limit (default 20), offset (default 0), order (default id_desc). Returns { pollClusters, pageCount }.

GET /external/poll-cluster/:id — get one

Returns the cluster with its rooms and polls.options.

PATCH /external/poll-cluster/:id — update

Same body as create (all fields optional). Changing scheduling fields reschedules the cluster.

DELETE /external/poll-cluster/:id — delete

POST /external/poll-cluster/:id/poll — add a question to a cluster

Body = Poll object.

PATCH /external/poll/:pollId — update a question

Partial Poll object. ⚠️ Sending options replaces the entire option set: all existing options are deleted and recreated from the array you send, so include every option you want to keep. Omit options to leave the current ones unchanged.

DELETE /external/poll/:pollId — delete a question

Poll object

Field Type Required Description
text string Yes The question
type POLL | QUIZ | RATING Yes See Poll types
isMultiple boolean No Allow multiple selected options. Default false
ratingScale integer ≥ 1 For RATING Number of points on the scale
pic string No Image URL for the question (or upload, see Media)
data LocalizedText[] No Translations of the question text (see Localization)
options Option[] Yes At least 1 (see Option object)

Option object

Field Type Required Description
text string Yes Answer text
pic string No Image URL for the answer
isRight boolean No Correct answer (for QUIZ). Default false
isCustom boolean No Turns this option into a free-text input. Default false
customPlaceholder string No Placeholder for the custom input
customMinLength integer ≥ 0 No Minimum length of the custom text
customMaxLength integer ≥ 1 No Maximum length of the custom text
data LocalizedText[] No Translations of the answer text (see Localization)

Localization

You can create a poll with content in several languages in one request. Both the Poll object and the Option object accept a data field: an array of { "lang": "...", "text": "..." } objects, one per language.

JSON
"data": [
  { "lang": "en", "text": "Who will score first?" },
  { "lang": "es", "text": "¿Quién marcará primero?" },
  { "lang": "fr", "text": "Qui marquera en premier ?" }
]

The user sees the version matching their interface language, with a fallback to the project default language. The base text field is used when no translation matches.

Example of a multilingual poll:

JSON
{
  "isStandalone": true,
  "roomIds": ["room-123"],
  "polls": [
    {
      "text": "Who will score first?",
      "type": "POLL",
      "isMultiple": false,
      "data": [
        { "lang": "en", "text": "Who will score first?" },
        { "lang": "es", "text": "¿Quién marcará primero?" }
      ],
      "options": [
        {
          "text": "Team A",
          "data": [
            { "lang": "en", "text": "Team A" },
            { "lang": "es", "text": "Equipo A" }
          ]
        },
        {
          "text": "Team B",
          "data": [
            { "lang": "en", "text": "Team B" },
            { "lang": "es", "text": "Equipo B" }
          ]
        }
      ]
    }
  ]
}

The same data field works in PATCH /external/poll-cluster/:id, POST /external/poll-cluster/:id/poll and PATCH /external/poll/:pollId.

Media

Send requests as multipart/form-data. Either pass pic as a URL string, or upload a file:

  • Poll endpoints (/poll, /poll/:pollId): attach the image in the pic field.
  • Cluster create/update: give each poll a temporary id, then attach its image in a field named pic_<id>. Uploaded images are resized automatically (max 600 px).

Example — a quiz published to two rooms

JSON
{
  "name": "Match prediction",
  "isStandalone": true,
  "roomIds": ["room-123", "room-456"],
  "startTime": "2026-07-01T18:00:00Z",
  "endTime": "2026-07-01T20:00:00Z",
  "polls": [
    {
      "text": "Who scores first?",
      "type": "QUIZ",
      "options": [
        { "text": "Team A", "isRight": true },
        { "text": "Team B", "isRight": false },
        { "text": "Other", "isCustom": true, "customPlaceholder": "Your guess", "customMaxLength": 50 }
      ]
    }
  ]
}

Example — a rating scale

JSON
{
  "name": "Post-match rating",
  "isStandalone": true,
  "roomIds": ["room-123"],
  "polls": [
    {
      "text": "Rate the match",
      "type": "RATING",
      "ratingScale": 5,
      "options": [{ "text": "Rating" }]
    }
  ]
}
Updated 1 month ago