June 18, 2026 · 10 min read

हमने अपने weekly retro को PollsLive API से ऑटोपायलट पर कैसे डाला

एक डेवलपर की पूरी कहानी: एक retro poll बनाएँ, एक live session खोलें, फिर results और एक CSV खींचें - सब कुछ cron पर चल रहे एक छोटे से Node स्क्रिप्ट से। असली /api/v1 endpoints, असली payloads।

By Maya Okafor · Platform engineer·DevelopersHow-toTeams & meetings

मैं एक प्लेटफ़ॉर्म इंजीनियर हूँ, और पहले हर शुक्रवार मैं वही retro deck हाथ से बनाने में दस मिनट खर्च करता था। वही पाँच सवाल, बस हफ़्ता अलग। ठेठ वो-काम जो किसी स्क्रिप्ट को करना चाहिए। तो मैंने इसे PollsLive API और एक cron job पर डाल दिया - अब poll खुद बन जाती है, एक live session अपने-आप खुल जाता है, और standup के बाद एक CSV हमारे Slack में आ जाता है। यहाँ ठीक-ठीक कैसे, असली endpoints और payloads के साथ।

Tip

इस guide को follow करने के लिए technical होना ज़रूरी नहीं। हर step PollsLive में साधारण buttons use करता है - कोई coding नहीं, आपकी audience के लिए कोई app install नहीं।

Auth: एक ही Bearer token

मैंने Studio → Developers में एक workspace API key बनाई (ये `plv_live_…` जैसी दिखती हैं) और उसे स्क्रिप्ट के environment में डाल दिया। हर request बस एक Bearer token है - server-to-server इस्तेमाल के लिए कोई OAuth झंझट नहीं।

# Base URL for all calls
export POLLSLIVE_API=https://pollslive.com/api/v1
export POLLSLIVE_KEY=plv_live_xxxxxxxxxxxxxxxxxxxx

# Every request carries the key as a Bearer token:
#   Authorization: Bearer $POLLSLIVE_KEY
# Rate limit: 120 requests/min per key (HTTP 429 if you exceed it).

Step 1 - retro poll बनाएँ

एक poll एक typed deck है: `content.questions` slides की एक array है, हर एक में एक `kind` discriminator। retro के लिए मैं एक scale, एक open_ended जो cloud के रूप में दिखती है, और fix पर वोट करने के लिए एक multiple_choice इस्तेमाल करता हूँ। `renderingMode: "LIVE"` के साथ `POST /polls` मुझे एक draft वापस देता है।

curl -sS -X POST "$POLLSLIVE_API/polls" \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Weekly retro - week of Jun 16",
    "renderingMode": "LIVE",
    "content": {
      "questions": [
        {
          "id": "health",
          "kind": "scale",
          "text": "How healthy did this sprint feel?",
          "min": 1, "max": 5,
          "minLabel": "Rough", "maxLabel": "Great"
        },
        {
          "id": "blockers",
          "kind": "open_ended",
          "text": "What slowed us down this sprint?",
          "render": "cloud",
          "maxLength": 120
        },
        {
          "id": "fix",
          "kind": "multiple_choice",
          "type": "single",
          "text": "What should we fix first next sprint?",
          "options": [
            { "id": "ci",       "label": "Stabilise the CI pipeline" },
            { "id": "tickets",  "label": "Tighter ticket acceptance criteria" },
            { "id": "wip",      "label": "Cap WIP and reviews SLA" },
            { "id": "meetings", "label": "Trim the meeting load" }
          ]
        }
      ]
    }
  }'

`201` response poll को एक `data` envelope में लपेट देता है - बाक़ी flow के लिए मैं `data.id` रखता हूँ, और join विवरण के लिए `data.accessPin` / `data.shareUrl`:

{
  "data": {
    "id": "poll_9aZ2kP",
    "slug": "weekly-retro-jun-16",
    "title": "Weekly retro - week of Jun 16",
    "renderingMode": "LIVE",
    "isPublished": false,
    "accessPin": "6098",
    "shareUrl": "https://pollslive.com/p/weekly-retro-jun-16",
    "createdAt": "2026-06-16T08:00:11.204Z"
  }
}

Step 2 - Publish करें, फिर एक live session खोलें

Publish करने से content का snapshot बन जाता है ताकि उसे present करना सुरक्षित रहे। `publish: true` के साथ एक `PATCH /polls/{id}` यह कर देता है; फिर `POST /sessions` presenter session शुरू करता है और join PIN के साथ एक one-time `hostToken` लौटाता है (यह host-authority सीक्रेट है - यह सिर्फ़ create पर ही लौटता है, इसलिए मैं इसे तुरंत संभाल लेता हूँ)।

# Publish the draft
curl -sS -X PATCH "$POLLSLIVE_API/polls/poll_9aZ2kP" \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "publish": true }'

# Open a presenter-paced live session
curl -sS -X POST "$POLLSLIVE_API/sessions" \
  -H "Authorization: Bearer $POLLSLIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pollId": "poll_9aZ2kP", "pace": "PRESENTER" }'
# → { "data": { "id": "ses_4dF1", "pin": "6098",
#       "joinUrl": "https://pollslive.com/join/6098",
#       "hostUrl": "https://pollslive.com/host/ses_4dF1",
#       "hostToken": "hst_…", "status": "LOBBY" } }

मेरा cron standup से एक मिनट पहले `joinUrl` और PIN टीम चैनल में पोस्ट कर देता है। टीम scan करती है, और कोड में मैंने जो slides बनाए वही वे देखते हैं - सबके जवाब देने के बाद यहाँ `health` slide का live नतीजा है:

Live scale
Join at the PIN 6098

इस sprint की सेहत कैसी लगी? (1 = खराब, 5 = बढ़िया)

5 - बढ़िया11% · 1
4 - अच्छा22% · 2
3 - ठीक22% · 2
2 - खराब33% · 3
1 - बहुत खराब11% · 1
वही slide जो मैंने JSON में परिभाषित किया, live रेंडर हुआ - कोई हाथ से deck बनाना नहीं।

Step 3 - standup के बाद results और एक CSV खींचें

जब session खत्म होता है, `GET /polls/{id}/results` tallies लौटाता है - `totalVotes`, choice slides के लिए एक `voteCounts` map, और एक `slides[]` array जिसमें per-kind aggregates (scale averages, grouped open-text, वगैरह) होते हैं।

curl -sS "$POLLSLIVE_API/polls/poll_9aZ2kP/results" \
  -H "Authorization: Bearer $POLLSLIVE_KEY"

{
  "data": {
    "pollId": "poll_9aZ2kP",
    "title": "Weekly retro - week of Jun 16",
    "closed": true,
    "totalVotes": 9,
    "voteCounts": { "ci": 4, "tickets": 3, "wip": 2, "meetings": 0 },
    "slides": [
      { "slideId": "health", "kind": "scale", "average": 2.9 },
      { "slideId": "blockers", "kind": "open_ended", "responseCount": 14 },
      { "slideId": "fix", "kind": "multiple_choice",
        "optionCounts": { "ci": 4, "tickets": 3, "wip": 2, "meetings": 0 } }
    ]
  }
}

आर्काइव के लिए, `GET /polls/{id}/export` एक RFC-4180 CSV स्ट्रीम करता है (slide नंबर, सवाल, type, answer label, count/value)। मैं इसे सेव करके Slack मैसेज में अटैच कर देता हूँ। पूरा post-standup कदम एक छोटा सा function है:

const API = process.env.POLLSLIVE_API;
const KEY = process.env.POLLSLIVE_KEY;
const auth = { Authorization: `Bearer ${KEY}` };

export async function summariseRetro(pollId) {
  const res = await fetch(`${API}/polls/${pollId}/results`, { headers: auth });
  if (res.status === 429) throw new Error("rate_limited"); // back off + retry
  if (!res.ok) throw new Error(`results ${res.status}`);
  const { data } = await res.json();

  const winner = Object.entries(data.voteCounts)
    .sort((a, b) => b[1] - a[1])[0];

  // Grab the CSV for the archive
  const csv = await fetch(`${API}/polls/${pollId}/export`, { headers: auth })
    .then((r) => r.text());

  return {
    health: data.slides.find((s) => s.slideId === "health")?.average,
    topFix: winner?.[0],
    voters: data.totalVotes,
    csv,
  };
}

बस यही पूरी बात है। retro deck खुद बनता है, session समय पर खुलता है, और summary + CSV अपने-आप पोस्ट हो जाते हैं। मुझे मेरे शुक्रवार के दस मिनट वापस मिल गए, और फ़ॉर्मैट हर हफ़्ते बिल्कुल एक जैसा है - जो कि retro से आप यही चाहते हैं।

सबसे अच्छी बात: जो slides मैं JSON में बताता हूँ वही slides टीम देखती है और उन पर वोट करती है। 'स्क्रिप्ट ने क्या बनाया' और 'हमने क्या चलाया' के बीच कोई फ़र्क नहीं।

पूरा endpoint reference और schemas इंटरैक्टिव API reference में हैं, और कहानी-वाला quickstart developer guide में है। मेरी अगली योजना: webhooks, ताकि Slack summary timer पर नहीं, बल्कि session खत्म होते ही फायर हो जाए - जो ठीक वही है जो webhooks वाला लेख कवर करता है।

Tip

Cron job se pichhle hafte ka retro deck clone karein aur automatically fresh link publish karein.

PollsLive Studio dashboard with poll list, left nav, and Create buttons.
Studio is your home for every poll you have created.
Results panel with stat tiles, breakdown by question, and export buttons.
The Results tab shows every answer and export options.

No-code alternative: · recurring polls without rebuilding.

PollsLive पर बनाएँ - अपने ही कोड से polls बनाएँ, live sessions चलाएँ, results खींचें, और webhooks पाएँ।

developer docs पढ़ें