June 18, 2026 · 10 min read
Como colocamos nossa retro semanal no piloto automático com a API do PollsLive
O passo a passo de uma desenvolvedora: criar uma enquete de retro, abrir uma sessão ao vivo e depois puxar resultados e um CSV - tudo a partir de um pequeno script Node num cron. Endpoints reais da /api/v1, payloads reais.
Sou engenheira de plataforma e, toda sexta-feira, eu gastava dez minutos montando à mão o mesmo deck de retro. As mesmas cinco perguntas, semana diferente. Clássico caso de algo-que-um-script-deveria-fazer. Então passei tudo para a API do PollsLive e um cron job - agora a enquete se cria sozinha, uma sessão ao vivo abre automaticamente e, depois da daily, um CSV cai no nosso Slack. Aqui vai exatamente como, com os endpoints e payloads reais.
Tip
Você não precisa ser técnico para seguir este guia. Cada passo usa botões simples no PollsLive - sem código, sem instalar app para seu público.
Autenticação: um único token Bearer
Gerei uma chave de API do workspace em Studio → Developers (elas têm o formato `plv_live_…`) e a coloquei no ambiente do script. Toda requisição é só um token Bearer - sem dança de OAuth para uso servidor-a-servidor.
# 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).Passo 1 - Criar a enquete de retro
Uma enquete é um deck tipado: `content.questions` é um array de slides, cada um com um discriminador `kind`. Para a retro eu uso uma scale, uma open_ended renderizada como nuvem e uma multiple_choice para votar na correção. Um `POST /polls` com `renderingMode: "LIVE"` me devolve um rascunho.
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" }
]
}
]
}
}'A resposta `201` envolve a enquete num envelope `data` - guardo o `data.id` para o resto do fluxo e o `data.accessPin` / `data.shareUrl` para os detalhes de entrada:
{
"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"
}
}Passo 2 - Publicar e depois abrir uma sessão ao vivo
Publicar tira um snapshot do conteúdo para que seja seguro apresentá-lo. Um `PATCH /polls/{id}` com `publish: true` faz isso; depois `POST /sessions` cria a sessão do apresentador e devolve o PIN de entrada mais um `hostToken` de uso único (o segredo de autoridade do host - ele só é retornado na criação, então o guardo imediatamente).
# 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" } }Meu cron posta a `joinUrl` e o PIN no canal do time um minuto antes da daily. O pessoal escaneia, e os slides que montei em código são o que eles veem - aqui está o resultado ao vivo do slide `health` depois que todo mundo respondeu:
Quão saudável esta sprint pareceu? (1 = difícil, 5 = ótima)
Passo 3 - Puxar resultados e um CSV depois da daily
Quando a sessão termina, `GET /polls/{id}/results` devolve as contagens - `totalVotes`, um mapa `voteCounts` para slides de escolha e um array `slides[]` com agregados por tipo (médias de escala, texto aberto agrupado etc.).
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 } }
]
}
}Para o arquivo, `GET /polls/{id}/export` faz streaming de um CSV no formato RFC-4180 (número do slide, pergunta, tipo, rótulo da resposta, contagem/valor). Eu salvo e anexo à mensagem do Slack. Todo o passo pós-daily é uma pequena função:
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,
};
}É isso tudo. O deck da retro se monta sozinho, a sessão abre na hora marcada e o resumo + CSV são postados automaticamente. Recuperei meus dez minutos de sexta-feira, e o formato é idêntico toda semana - que é exatamente o que se quer de uma retro.
A parte mais bacana: os slides que descrevo em JSON são os mesmos slides que o time vê e vota. Sem divergência entre 'o que o script fez' e 'o que rodamos'.
A referência completa de endpoints e os schemas estão na referência de API interativa, e o quickstart narrativo está no guia para desenvolvedores. Próximo na minha lista: webhooks, para que o resumo do Slack dispare no instante em que a sessão termina, em vez de num timer - que é exatamente o que o artigo sobre webhooks cobre.
Tip
Use um cron job para clonar o deck de retro da semana passada e publicar um link novo automaticamente.


Alternativa sem código: enquetes recorrentes sem reconstruir.
Desenvolva no PollsLive - crie enquetes, conduza sessões ao vivo, obtenha resultados e receba webhooks pelo seu próprio código.
Leia a documentação para desenvolvedores