June 18, 2026 · 10 min read

Comment on a mis notre rétro hebdomadaire en pilote automatique avec l'API PollsLive

Le guide d'une développeuse : créer un sondage de rétro, ouvrir une session live, puis récupérer les résultats et un CSV - le tout depuis un petit script Node sur un cron. De vrais endpoints /api/v1, de vrais payloads.

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

Je suis ingénieure plateforme, et chaque vendredi je passais dix minutes à reconstruire à la main le même deck de rétro. Les cinq mêmes questions, une semaine différente. Typiquement le genre de truc qu'un script devrait faire. Alors je l'ai basculé sur l'API PollsLive et un cron - le sondage se crée désormais tout seul, une session live s'ouvre automatiquement, et après le standup un CSV atterrit dans notre Slack. Voici exactement comment, avec les vrais endpoints et payloads.

Tip

You do not need to be technical to follow this guide. Every step uses plain buttons in PollsLive - no coding, no app install for your audience.

Auth : un seul token Bearer

J'ai généré une clé d'API d'espace de travail dans Studio → Developers (elles ressemblent à `plv_live_…`) et je l'ai placée dans l'environnement du script. Chaque requête n'est qu'un token Bearer - pas de valse OAuth pour un usage serveur à serveur.

auth
# 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).

Étape 1 - Créer le sondage de rétro

Un sondage est un deck typé : `content.questions` est un tableau de slides, chacune avec un discriminant `kind`. Pour la rétro j'utilise une scale, une open_ended rendue en nuage, et une multiple_choice pour voter sur le correctif. `POST /polls` avec `renderingMode: "LIVE"` me renvoie un brouillon.

POST /polls
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" }
          ]
        }
      ]
    }
  }'

La réponse `201` enveloppe le sondage dans une enveloppe `data` - je garde `data.id` pour la suite du flux, et `data.accessPin` / `data.shareUrl` pour les détails de connexion :

201 Created
{
  "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"
  }
}

Étape 2 - Publier, puis ouvrir une session live

Publier fige le contenu pour qu'il soit sûr à présenter. Un `PATCH /polls/{id}` avec `publish: true` fait l'affaire ; puis `POST /sessions` lance la session présentateur et renvoie le PIN de connexion plus un `hostToken` à usage unique (le secret d'autorité hôte - il n'est renvoyé qu'à la création, alors je le stocke immédiatement).

PATCH /polls/{id} → POST /sessions
# 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" } }

Mon cron poste le `joinUrl` et le PIN dans le canal de l'équipe une minute avant le standup. L'équipe scanne, et les slides que j'ai construites en code sont ce qu'ils voient - voici le résultat live de la slide `health` une fois que tout le monde a répondu :

Live scale
Join at the PIN 6098

À quel point ce sprint a-t-il semblé sain ? (1 = difficile, 5 = excellent)

5 - Excellent11% · 1
4 - Bien22% · 2
3 - Correct22% · 2
2 - Difficile33% · 3
1 - Mauvais11% · 1
La slide que j'ai définie en JSON, rendue en live - sans construire de deck à la main.

Étape 3 - Récupérer les résultats et un CSV après le standup

Quand la session se termine, `GET /polls/{id}/results` renvoie les décomptes - `totalVotes`, une map `voteCounts` pour les slides à choix, et un tableau `slides[]` avec des agrégats par type (moyennes de scale, texte libre regroupé, etc.).

GET /polls/{id}/results
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 } }
    ]
  }
}

Pour l'archive, `GET /polls/{id}/export` diffuse un CSV RFC-4180 (numéro de slide, question, type, libellé de réponse, décompte/valeur). Je l'enregistre et je le joins au message Slack. Toute l'étape post-standup tient en une petite fonction :

summarise.mjs (Node 18+)
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,
  };
}

Et voilà tout. Le deck de rétro se construit tout seul, la session s'ouvre à l'heure, et le résumé + le CSV se postent automatiquement. J'ai récupéré mes dix minutes du vendredi, et le format est identique chaque semaine - ce qui est exactement ce qu'on attend d'une rétro.

Le plus chouette : les slides que je décris en JSON sont exactement celles que l'équipe voit et sur lesquelles elle vote. Aucun décalage entre « ce que le script a fabriqué » et « ce qu'on a lancé ».

La référence complète des endpoints et les schémas sont dans la référence d'API interactive, et le démarrage rapide narratif est dans le guide développeur. Prochain sur ma liste : les webhooks, pour que le résumé Slack se déclenche à l'instant où la session se termine plutôt que sur une minuterie - ce que couvre justement l'article sur les webhooks.

Tip

Use a cron job to clone last week's retro deck and publish a fresh link automatically.

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.

Construisez sur PollsLive - créez des sondages, pilotez des sessions live, récupérez des résultats et recevez des webhooks depuis votre propre code.

Lire la doc développeur