Appearance
Öffentliche API
Mit der öffentlichen API (/api/v1) verbindest du eigene Systeme mit PollYou: Umfragen anlegen und veröffentlichen, Antworten in ein CRM oder Data Warehouse übernehmen, Kennzahlen in ein BI-Tool laden oder Antworten auf Löschanfragen hin entfernen.
Die vollständige Liste der Endpunkte mit Parametern und Feldern steht in der Referenz v1. Für KI-Assistenten gibt es außerdem den MCP-Server, der dieselben Fähigkeiten als MCP-Tools bereitstellt.
API-Schlüssel
Die API authentifiziert sich mit API-Schlüsseln deiner Organisation. Admins und Inhaber legen sie im Dashboard unter Einstellungen → API-Schlüssel an:
- Name vergeben, z. B. „CRM-Synchronisation“ – gib jedem System einen eigenen Schlüssel.
- Scopes wählen: nur die Rechte, die das System braucht (siehe unten).
- Optional ein Ablaufdatum setzen. Ohne Datum gilt der Schlüssel, bis er widerrufen wird.
Nach dem Anlegen zeigt das Dashboard den vollständigen Schlüssel genau einmal an. Kopiere ihn sofort in deinen Passwort-Manager oder Secret-Store: PollYou speichert nur einen Hash und kann den Schlüssel später nicht mehr anzeigen. In der Liste siehst du danach nur noch das Präfix (z. B. py_live_k3x9a2bq…), die Scopes und wann der Schlüssel zuletzt benutzt wurde.
Ein Schlüssel sieht so aus:
py_live_k3x9a2bq_Q8yS0d… (py_live_ + 8 Zeichen Präfix + _ + 40 Zeichen Geheimnis)Widerrufen wirkt sofort: Anfragen mit dem Schlüssel werden danach mit 401 abgelehnt. Anlegen und Widerrufen stehen im Audit-Log der Organisation.
Schlüssel geheim halten
Ein API-Schlüssel gehört nur auf Server, nie in Browser-Code, Apps oder Repositories. Ist ein Schlüssel nach außen gelangt, widerrufe ihn und lege einen neuen an.
Authentifizierung
Sende den Schlüssel als Bearer-Token:
bash
curl https://api.pollyou.example/api/v1/surveys \
-H "Authorization: Bearer $POLLYOU_API_KEY"Ein Schlüssel gehört zu genau einer Organisation, deshalb ist der Header X-Organization-Id nicht nötig. Sendest du ihn trotzdem, muss er die Organisation des Schlüssels nennen – sonst antwortet die API mit 403.
| Status | Bedeutung |
|---|---|
401 | Schlüssel fehlt, ist ungültig, abgelaufen oder widerrufen (detail sagt, was) |
403 | Dem Schlüssel fehlt der nötige Scope, oder X-Organization-Id passt nicht |
404 | Die Ressource existiert nicht – oder gehört einer anderen Organisation |
422 | Ungültige Eingabe; violations nennt Feld (propertyPath) und Grund (message) |
429 | Rate-Limit überschritten, siehe unten |
Fehler kommen als Problem-JSON (application/problem+json) mit title, status und detail.
Die Anmeldung des Dashboards (Zugangstokens von Personen) funktioniert für /api/v1 nicht, und API-Schlüssel funktionieren nicht für die interne API des Dashboards.
Scopes
Jeder Endpunkt verlangt einen Scope. Ein …:write-Scope enthält den passenden …:read-Scope.
| Scope | Erlaubt |
|---|---|
surveys:read | Umfragen auflisten und mit Struktur abrufen |
surveys:write | Umfragen anlegen, Titel/Beschreibung ändern, veröffentlichen, beenden (enthält surveys:read) |
responses:read | Antworten einer Umfrage auflisten und einzeln mit allen Angaben abrufen |
responses:write | Antworten endgültig löschen (enthält responses:read) |
analytics:read | Kennzahlen und Ergebnisse pro Frage abrufen |
Fehlt der Scope, antwortet die API mit 403 und "detail": "The API key lacks the scope \"responses:read\".".
Datenschutz
responses:read gibt Zugriff auf einzelne Antworten inklusive Kontextdaten (Land, Gerät, UTM-Parameter, Metadaten der Einbettung). Vergib den Scope nur an Systeme, die diese Daten wirklich verarbeiten dürfen; für Dashboards reicht meist analytics:read.
Rate-Limits
Pro Schlüssel sind 600 Anfragen pro Minute erlaubt. Jede Antwort enthält:
| Header | Inhalt |
|---|---|
X-RateLimit-Limit | Anfragen pro Minute |
X-RateLimit-Remaining | Verbleibende Anfragen im aktuellen Fenster |
X-RateLimit-Reset | Unix-Zeit, ab der die nächste Anfrage frühestens wieder angenommen wird |
Ist das Limit erreicht, antwortet die API mit 429 Too Many Requests und Retry-After (Sekunden). Warte mindestens so lange, bevor du es erneut versuchst. Brauchst du mehr Durchsatz für einen Import, verteile die Arbeit nicht auf mehrere Schlüssel, sondern sprich uns an.
Versionierung
Die Version steht im Pfad: /api/v1. Für v1 gilt:
- Felder, Parameter und Endpunkte kommen nur hinzu. Nichts wird umbenannt, entfernt oder ändert seine Bedeutung.
- Dein Client muss unbekannte Felder ignorieren – neue Felder sind keine Breaking Changes.
- Neue Fragetypen können in
pageseiner Umfrage und inquestionsder Auswertung auftauchen; behandle unbekanntetype-Werte tolerant. - Breaking Changes erscheinen als neue Version (
/api/v2), die eine Übergangszeit lang parallel zu v1 läuft.
Die API spricht reines JSON (application/json); Änderungen per PATCH erwarten application/merge-patch+json.
Beispiele
Umfragen auflisten
bash
curl "https://api.pollyou.example/api/v1/surveys?status=live" \
-H "Authorization: Bearer $POLLYOU_API_KEY"json
{
"items": [
{
"id": "01a12b79-3855-7453-b69a-a847cfe69ce1",
"publicId": "Abc123XyZ0",
"type": "survey",
"title": "Kundenzufriedenheit",
"status": "live",
"questionCount": 5,
"publishedVersion": 2,
"publishedAt": "2026-10-01T08:00:00+00:00",
"hasUnpublishedChanges": false,
"createdAt": "2026-09-20T10:00:00+00:00",
"updatedAt": "2026-10-01T08:00:00+00:00"
}
],
"page": 1,
"itemsPerPage": 25,
"totalItems": 1
}Weitere Seiten mit ?page=2.
Umfrage anlegen und veröffentlichen
bash
# Entwurf anlegen (scope surveys:write) – eine Abstimmung startet mit einer Frage und zwei Optionen
curl https://api.pollyou.example/api/v1/surveys \
-H "Authorization: Bearer $POLLYOU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "poll", "title": "Welches Feature zuerst?"}'
# Titel ändern
curl -X PATCH https://api.pollyou.example/api/v1/surveys/$SURVEY_ID \
-H "Authorization: Bearer $POLLYOU_API_KEY" \
-H "Content-Type: application/merge-patch+json" \
-d '{"title": "Welches Feature bauen wir zuerst?"}'
# Veröffentlichen und später beenden
curl -X POST https://api.pollyou.example/api/v1/surveys/$SURVEY_ID/publish \
-H "Authorization: Bearer $POLLYOU_API_KEY"
curl -X POST https://api.pollyou.example/api/v1/surveys/$SURVEY_ID/close \
-H "Authorization: Bearer $POLLYOU_API_KEY"Fragen und Optionen bearbeitest du im Dashboard. Im Audit-Log erscheint als handelnde Stelle der API-Schlüssel (Name und Präfix).
Antworten abholen (inkrementell)
bash
curl "https://api.pollyou.example/api/v1/surveys/$SURVEY_ID/responses?from=2026-10-01&timezone=Europe/Berlin&limit=100" \
-H "Authorization: Bearer $POLLYOU_API_KEY"json
{
"items": [
{
"id": "01a12b7a-cd25-7eb6-90e5-64dd7baa2772",
"status": "completed",
"startedAt": "2026-10-11T09:12:03+00:00",
"completedAt": "2026-10-11T09:13:10+00:00",
"durationMs": 67000,
"channel": "script",
"country": "DE",
"versionNumber": 2,
"excluded": false,
"answers": { "nps": 9, "plan": "Pro" }
}
],
"totalItems": 1342,
"nextCursor": "eyJ2IjoiMjAyNi0xMC0xMVQwOToxMzoxMC4wMDBaIiwiaWQiOiIwMWExMmI3YS0uLi4ifQ"
}Die Liste ist nach Abschlusszeit sortiert (neueste zuerst). Für die nächste Seite übergibst du nextCursor als cursor; der Cursor bleibt stabil, auch wenn währenddessen neue Antworten eintreffen. nextCursor: null heißt: letzte Seite. Ausgeschlossene Antworten (Spam, Tests) kommen nur mit includeExcluded=true, laufende Antworten mit status=started oder status=all.
Alle Angaben einer Antwort, inklusive Rohwerten, Anzeige-Texten und Zeitpunkten pro Frage:
bash
curl https://api.pollyou.example/api/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $POLLYOU_API_KEY"Antwort löschen
bash
curl -X DELETE https://api.pollyou.example/api/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $POLLYOU_API_KEY" # 204, scope responses:writeDie Antwort wird endgültig gelöscht, die Auswertungen werden neu berechnet. Die Löschung steht im Audit-Log.
Kennzahlen abrufen
bash
curl "https://api.pollyou.example/api/v1/surveys/$SURVEY_ID/analytics?from=2026-10-01&to=2026-10-31&timezone=Europe/Berlin" \
-H "Authorization: Bearer $POLLYOU_API_KEY"json
{
"surveyId": "01a12b79-3855-7453-b69a-a847cfe69ce1",
"meta": {
"source": "rollup",
"timezone": "Europe/Berlin",
"from": "2026-10-01T00:00:00+02:00",
"to": "2026-11-01T00:00:00+01:00"
},
"overview": {
"impressions": 5120,
"starts": 1830,
"completions": 1342,
"startRate": 0.357,
"completionRate": 0.733,
"averageDurationMs": 71000,
"medianDurationMs": 58000
},
"totalResponses": 1342,
"questions": [
{
"key": "nps",
"type": "nps",
"title": "Wie wahrscheinlich …?",
"totalAnswers": 1342,
"nps": { "score": 41.2, "promoters": 702, "passives": 410, "detractors": 230 }
}
]
}Ohne from/to gelten die letzten 30 Tage inklusive heute. Es zählen dieselben Antworten wie im Dashboard: abgeschlossen und nicht ausgeschlossen.
OpenAPI
Das OpenAPI-Dokument der öffentlichen API liefert die API selbst unter GET /api/v1/openapi.json (ohne Schlüssel). Du kannst es in Postman oder Insomnia importieren oder daraus einen Client generieren, z. B. mit openapi-typescript. Eine Kopie liegt in der Doku: Referenz v1.