Polls & predictions

With the polls:manage scope, your app can run polls and predictions on a channel, the same ones the creator starts from the Stream Manager. Viewers vote and predict on the watch page; your app starts, ends and settles them.

The shapes are Twitch's Helix ones (data: […], uppercase statuses), so a Twitch bot ports with a base-URL change. To hear about votes and predictions as they happen, also ask for events:read and listen for the EventSub types below.

One poll and one prediction can run on a channel at a time. Starting either needs the channel to be live. Predictions use channel points only, never money, so the channel needs channel points turned on.

Get the poll

GET /api/apps/channels/{channelId}/polls returns the running poll, or the latest one if none is running. data is empty when the channel has never run a poll.

{
  "success": true,
  "data": [
    {
      "id": "6c1f0e2a-8b47-4d3e-9a15-0f7e2c4b9d31",
      "broadcaster_id": "1f9a3b6c-…",
      "broadcaster_name": "Pixel Panda",
      "broadcaster_login": "pixelpanda",
      "title": "Which map next?",
      "choices": [
        { "id": "c0d1…", "title": "Dust", "votes": 41, "channel_points_votes": 6, "bits_votes": 0 },
        { "id": "c0d2…", "title": "Mirage", "votes": 57, "channel_points_votes": 20, "bits_votes": 0 }
      ],
      "bits_voting_enabled": false,
      "bits_per_vote": 0,
      "channel_points_voting_enabled": true,
      "channel_points_per_vote": 100,
      "status": "ACTIVE",
      "duration": 120,
      "started_at": "2026-10-11T20:40:00Z",
      "ended_at": null
    }
  ]
}

status is ACTIVE, COMPLETED (time ran out), TERMINATED (ended early) or ARCHIVED (ended and hidden from viewers). votes counts every vote; channel_points_votes is how many of them were bought with points. Xive has no Bits, so the Bits fields are always off.

Start a poll

POST /api/apps/channels/{channelId}/polls

FieldTypeNotes
titlestringRequired. Up to 60 characters.
choicesarrayRequired. 2–5 of {"title": …}, up to 25 characters each.
durationintegerRequired. Seconds, 15–1800.
channel_points_voting_enabledbooleanOptional. Lets viewers buy extra votes with channel points.
channel_points_per_voteintegerRequired with the above. 1–1,000,000.
curl -X POST https://api.thexive.com/api/apps/channels/CHANNEL_ID/polls \
  -H "Authorization: Bearer $XIVE_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"title": "Which map next?", "choices": [{"title": "Dust"}, {"title": "Mirage"}], "duration": 120}'

Answers with the new poll in data. Every viewer gets one free vote; with channel-points voting on, they can add more votes for points. The title and choices go through Xive's content filter, which answers 400 on a refusal. 409 when a poll is already running or the channel isn't live.

End a poll

PATCH /api/apps/channels/{channelId}/polls with {"id": …, "status": "TERMINATED"} ends it now and shows the result. ARCHIVED ends it and hides it from viewers; it also works on a poll that has already ended. A poll that has already ended answers 409.

Get the prediction

GET /api/apps/channels/{channelId}/predictions returns the open prediction (taking predictions, or locked and waiting for a result), or the latest one.

{
  "success": true,
  "data": [
    {
      "id": "9a4e7d10-…",
      "broadcaster_id": "1f9a3b6c-…",
      "broadcaster_name": "Pixel Panda",
      "broadcaster_login": "pixelpanda",
      "title": "Do we beat the boss?",
      "winning_outcome_id": null,
      "outcomes": [
        {
          "id": "o1…", "title": "Yes", "users": 12, "channel_points": 8400, "color": "BLUE",
          "top_predictors": [
            { "user_id": "…", "user_name": "Rook", "user_login": "rook", "channel_points_used": 2500, "channel_points_won": null }
          ]
        },
        { "id": "o2…", "title": "No", "users": 9, "channel_points": 5100, "color": "PINK", "top_predictors": null }
      ],
      "prediction_window": 120,
      "status": "LOCKED",
      "created_at": "2026-10-11T20:41:00Z",
      "ended_at": null,
      "locked_at": "2026-10-11T20:43:00Z"
    }
  ]
}

status is ACTIVE, LOCKED, RESOLVED or CANCELED. Up to 10 top predictors per outcome. With two outcomes they are BLUE and PINK; with more, all BLUE.

Start a prediction

POST /api/apps/channels/{channelId}/predictions with title (up to 45 characters), outcomes (2–10 of {"title": …}, up to 25 characters each) and prediction_window (seconds, 30–1800).

curl -X POST https://api.thexive.com/api/apps/channels/CHANNEL_ID/predictions \
  -H "Authorization: Bearer $XIVE_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"title": "Do we beat the boss?", "outcomes": [{"title": "Yes"}, {"title": "No"}], "prediction_window": 120}'

Viewers put channel points on one outcome (and can add more to it), up to 250,000 points each. When the window closes, the prediction locks by itself.

Lock, resolve or cancel

PATCH /api/apps/channels/{channelId}/predictions with {"id": …, "status": …}:

StatusDoesWorks on
LOCKEDStop taking predictions now.ACTIVE
RESOLVEDPick the winner (send winning_outcome_id). The winners share the whole pot.ACTIVE, LOCKED
CANCELEDGive everyone their points back.ACTIVE, LOCKED
curl -X PATCH https://api.thexive.com/api/apps/channels/CHANNEL_ID/predictions \
  -H "Authorization: Bearer $XIVE_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"id": "PREDICTION_ID", "status": "RESOLVED", "winning_outcome_id": "OUTCOME_ID"}'

A prediction is settled exactly once: a second resolve or cancel (from your app, the creator or another tool) answers 409 and pays nothing.

How the pot is paid

The pot is every point on every outcome. Each winner gets pot × their points ÷ the winning outcome's points, rounded down, so they always get at least their own points back. Rounding leaves a few points over (fewer than the number of winners); those go one each to the winners whose share was rounded down the most, ties going to the bigger prediction, then the earlier one. Every point in the pot is paid out. If nobody picked the winning outcome, everyone gets their points back.

EventSub

With events:read: channel.poll.begin, channel.poll.progress, channel.poll.end, channel.prediction.begin, channel.prediction.progress, channel.prediction.lock and channel.prediction.end, in Twitch's shapes. Progress events come at most about once a second.

{
  "subscription_type": "channel.prediction.end",
  "event": {
    "id": "9a4e7d10-…",
    "broadcaster_user_id": "1f9a3b6c-…", "broadcaster_user_login": "pixelpanda", "broadcaster_user_name": "Pixel Panda",
    "title": "Do we beat the boss?",
    "winning_outcome_id": "o1…",
    "outcomes": [
      { "id": "o1…", "title": "Yes", "color": "blue", "users": 12, "channel_points": 8400,
        "top_predictors": [ { "user_id": "…", "user_login": "rook", "user_name": "Rook", "channel_points_won": 4011, "channel_points_used": 2500 } ] }
    ],
    "status": "resolved",
    "started_at": "2026-10-11T20:41:00Z",
    "ended_at": "2026-10-11T20:50:12Z"
  }
}

channel_points_won is null in progress and lock events, and 0 for losers or a canceled prediction. A poll's channel.poll.end carries status (completed, terminated or archived) and ended_at.