Developers

Developer API

Automate PollsLive from your own backend - create polls, read results, run live sessions, and receive webhooks. Available on Pro and Enterprise plans.

Overview

The Developer API is a REST API under /api/v1. All requests and responses are JSON. The full, interactive contract lives in the API reference; this page gets you to your first successful call.

Authentication

Authenticate with a workspace API key sent as a Bearer token. Generate one in Studio → Developers (Pro/Enterprise). The secret is shown once - store it somewhere safe; if you lose it, revoke the key and create a new one.

Authorization header
Authorization: Bearer plv_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx

Keys act with admin authority within their workspace. Never expose a key in client-side code - call the API from your server.

You can also authenticate using an OAuth 2.0 Client Credentials access token for machine-to-machine integrations.

Quickstart

Create a poll, publish it, then read results:

Create a poll
curl -X POST https://pollslive.com/api/v1/polls \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Lunch vote",
    "content": {
      "questions": [{
        "id": "q1", "kind": "multiple_choice", "text": "Where to?",
        "type": "single",
        "options": [
          { "id": "a", "label": "Tacos" },
          { "id": "b", "label": "Sushi" }
        ]
      }]
    }
  }'
Publish it (use the id from the create response)
curl -X PATCH https://pollslive.com/api/v1/polls/POLL_ID \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "publish": true }'
Read results
curl https://pollslive.com/api/v1/polls/POLL_ID/results \
  -H "Authorization: Bearer $POLLSLIVE_KEY"

Question types

A poll is a deck of typed slides. Set kind on each slide. All seven kinds can be authored via the API:

  • multiple_choice - type (single/multiple), options[]. Votable async.
  • quiz - options[], correctOptionIds[], timeLimitSec, points, speedBonus.
  • scale - min, max, minLabel, maxLabel, statements[].
  • ranking - options[] (respondents order them).
  • open_ended - maxLength, render (list/cloud).
  • qa - moderated, allowUpvotes.
  • content - display-only.
A scale slide and a quiz slide
{
  "questions": [
    {
      "id": "s1", "kind": "scale", "text": "How likely are you to recommend us?",
      "min": 0, "max": 10, "minLabel": "Not likely", "maxLabel": "Very likely"
    },
    {
      "id": "q2", "kind": "quiz", "text": "Capital of France?",
      "options": [{ "id": "a", "label": "Paris" }, { "id": "b", "label": "Rome" }],
      "correctOptionIds": ["a"], "timeLimitSec": 20, "points": 1000
    },
    {
      "id": "q3", "kind": "ranking", "text": "Rank these features by importance",
      "options": [
        { "id": "r1", "label": "Speed" },
        { "id": "r2", "label": "Reliability" },
        { "id": "r3", "label": "Price" }
      ]
    },
    {
      "id": "q4", "kind": "open_ended", "text": "Any other feedback?",
      "maxLength": 300, "render": "list"
    },
    {
      "id": "q5", "kind": "qa", "text": "Questions for the presenter",
      "moderated": true, "allowUpvotes": true
    }
  ]
}

Images, video & links

Any slide and any option can carry media. Upload or pass a URL to POST /media and embed the returned object. Images are downloaded, re-encoded to WebP, and re-hosted (smaller payloads). YouTube videos and web links keep their URL and render client-side, so you never pay to host video. You can also pass media: { type, url } inline on a slide/option and the API resolves it when you save.

Ingest an image, then embed it
# 1) Ingest an image (returns { data: { type, url, storedUrl, width, height } })
curl -X POST https://pollslive.com/api/v1/media \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/cat.jpg" }'

# 2) Embed the storedUrl on a slide option
{ "id": "a", "label": "Option A", "media": { "type": "image", "url": "https://cdn.pollslive.com/media/abc.webp" } }

# Or pass the original URL inline - the API resolves it on save:
{ "id": "a", "label": "Option A", "media": { "type": "image", "url": "https://example.com/cat.jpg" } }

# YouTube on a question slide
{ "id": "q1", "kind": "content", "text": "Watch this first",
  "media": { "type": "youtube", "url": "https://youtu.be/dQw4w9WgXcQ" } }

Responses & results

multiple_choice slides take votes via POST /polls/{id}/votes. Every other kind takes async responses via POST /polls/{id}/responses - send the field matching the slide (scaleValue, rankingOrder, text, or optionIds). Read per-slide aggregates from GET /polls/{id}/results.

Record a scale response
curl -X POST https://pollslive.com/api/v1/polls/POLL_ID/responses \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "voterId": "user-123", "slideId": "s1", "scaleValue": 9 }'
Record a ranking response
curl -X POST https://pollslive.com/api/v1/polls/POLL_ID/responses \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "voterId": "user-123",
    "slideId": "q3",
    "rankingOrder": ["r2", "r1", "r3"]
  }'
Record an open-ended response
curl -X POST https://pollslive.com/api/v1/polls/POLL_ID/responses \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "voterId": "user-123", "slideId": "q4", "text": "Great product!" }'

Live sessions & session control

A live session lets you drive a poll in real time in front of an audience. Create a session via the API, share the PIN or QR code with your audience, then control pacing and results visibility with the control endpoint.

Create a session
curl -X POST https://pollslive.com/api/v1/sessions \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pollId": "POLL_ID" }'
# Response includes: id, pin, status, currentSlideIndex, hostToken (once)
Advance to the next slide
curl -X POST https://pollslive.com/api/v1/sessions/SESSION_ID/control \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "action": "next" }'

All session control actions

POST to /sessions/{id}/control with one of these action strings:

ActionDescription
startOpen the session and broadcast the first slide.
nextAdvance to the next slide.
prevGo back to the previous slide.
gotoJump to a specific slide - pass slideIndex (0-based) alongside action.
showResultsReveal live results for the current slide to participants.
hideResultsHide results (stop showing them to participants).
lockLock answers - participants can no longer submit for the current slide.
unlockUnlock answers so participants can respond.
endClose the session. Participants see a results summary.
Jump to slide 2 (0-based)
{ "action": "goto", "slideIndex": 2 }

AI branching

AI branching adds conditional skip logic to your poll with a plain-English instruction - no need to manually wire conditions. Pro and Enterprise only. The API attempts our AI provider (OpenRouter) and falls back to a rule-based parser when it's unavailable.

Apply branching to a poll
curl -X POST https://pollslive.com/api/v1/polls/POLL_ID/branch \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "If the respondent selects Yes on question 1, skip to question 3. Otherwise go to question 2."
  }'
# Response: { data: { draftJson: { ... conditions: [...] }, source: "openai" | "rules" } }

Exporting results

Download aggregate poll results as a UTF-8 RFC-4180 CSV file. Each row contains the slide number, question text, type, answer label, and count or value. Compatible with Excel, Google Sheets, and any CSV tool. Pro and Enterprise only.

Export a poll's results as CSV
curl https://pollslive.com/api/v1/polls/POLL_ID/export \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  --output results.csv

# CSV structure:
# Slide, Question, Type, Answer / Label, Count / Value
# 1, "Where to?", multiple_choice, Tacos, 12
# 1, "Where to?", multiple_choice, Sushi, 8
# 2, "Rate your experience", scale, Average, 8.50
# 2, "Rate your experience", scale, Rating 10, 5

Endpoints

  • Polls - GET/POST /polls, GET/PATCH/DELETE /polls/{id}
  • Results - GET /polls/{id}/results, GET/POST /polls/{id}/responses
  • Votes - GET/POST /polls/{id}/votes
  • Media - POST /media
  • Sessions - POST /sessions, GET /sessions/{id}, POST /sessions/{id}/control
  • AI - POST /polls/{id}/branch
  • Export - GET /polls/{id}/export

See request/response shapes and try calls live in the API reference.

Errors & rate limits

Errors use a stable envelope:

Error response
{ "error": { "code": "not_found", "message": "Poll not found." } }

Common codes: 401 invalid/missing key, 402 plan upgrade required, 404 not found, 409 conflict (e.g. already voted, poll closed), 422 validation failed, 429 rate limited.

Rate limits

The API allows 120 requests per minute per key for all endpoints. Media ingestion (POST /media) is separately capped at 30 requests per minute. Limits reset in 60-second sliding windows. HTTP 429 is returned when exceeded - back off and retry.

EndpointLimit
All endpoints120 req / min
POST /media30 req / min

OAuth2 (Enterprise)

Enterprise workspaces can use OAuth2 client-credentials in place of static keys. This is rolling out - contact us to enable it for your account.

Still have questions?

Our team is happy to help.

Contact us
Developer API - Quickstart & Authentication | PollsLive | PollsLive