Jede NueForm-Webhook-Anfrage sendet eine JSON-Payload im Anfrage-Body. Diese Seite dokumentiert das vollständige Payload-Schema für jeden Ereignistyp.
Gemeinsame Struktur
Alle Webhook-Payloads teilen sich diese Felder auf oberster Ebene:
| Feld | Typ | Beschreibung |
|---|---|---|
event | string | Der Ereignistyp (z. B. form.submitted) |
formId | string | Die eindeutige ID des Formulars |
formTitle | string | Der Titel des Formulars zum Zeitpunkt der Übermittlung |
responseId | string | Die eindeutige ID der Response |
answers | array | Array von Antwortobjekten |
respondent | object oder null | Identität der angemeldeten befragten Person, wenn das Formular einen Login erforderte. null bei anonymen Übermittlungen. Siehe Identität der Befragten. |
submittedAt | string | ISO-8601-Zeitstempel des Ereignisversands |
form.submitted-Payload
Diese Payload wird gesendet, wenn eine befragte Person eine vollständige Formularantwort übermittelt.
Vollständiges Beispiel
{
"event": "form.submitted",
"formId": "507f1f77bcf86cd799439011",
"formTitle": "Customer Feedback Survey",
"responseId": "507f1f77bcf86cd799439022",
"answers": [
{
"questionId": "507f1f77bcf86cd799439033",
"value": "Jane Doe",
"label": "What's your name?",
"type": "short_text"
},
{
"questionId": "507f1f77bcf86cd799439044",
"value": "jane@example.com",
"label": "What's your email address?",
"type": "email"
},
{
"questionId": "507f1f77bcf86cd799439055",
"value": 4,
"label": "How would you rate your experience?",
"type": "rating"
},
{
"questionId": "507f1f77bcf86cd799439066",
"value": "The onboarding flow was smooth and intuitive.",
"label": "What did you like most?",
"type": "long_text"
},
{
"questionId": "507f1f77bcf86cd799439077",
"value": ["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "9b7e2d41-5c3f-4a8e-b6d0-1f2a4c6e8b93"],
"label": "Which features do you use?",
"type": "multiple_choice"
},
{
"questionId": "507f1f77bcf86cd799439088",
"value": true,
"label": "Would you recommend us?",
"type": "yes_no"
}
],
"respondent": {
"id": "507f1f77bcf86cd799439016",
"name": "Jane Smith",
"email": "jane@example.com",
"auth_method": "sso"
},
"submittedAt": "2025-03-15T14:32:07.123Z"
}
Feldreferenz
Felder auf oberster Ebene
event --- string
Bei diesem Ereignistyp immer "form.submitted".
formId --- string
Die MongoDB-ObjectId des Formulars. Das ist ein 24-stelliger Hexadezimal-String.
formTitle --- string
Der menschenlesbare Titel des Formulars zum Zeitpunkt des Webhook-Versands. Beachte: Wenn du das Formular später umbenennst, enthalten bereits zugestellte Webhooks weiterhin den alten Titel.
responseId --- string
Die MongoDB-ObjectId der gespeicherten Response. Damit kannst du die vollständige Response über die Responses-API abrufen oder sie als Idempotenzschlüssel zum Deduplizieren von Webhook-Zustellungen verwenden.
submittedAt --- string
ISO-8601-Zeitstempel, der angibt, wann der Webhook versendet wurde. Er wird zum Versandzeitpunkt erzeugt und liegt sehr nah am submittedAt-Feld der Response in der Datenbank (ist aber nicht zwingend identisch).
respondent --- object oder null
Identität des angemeldeten Benutzers, der die Response übermittelt hat — nur enthalten, wenn das Formular einen Login erforderte (requireLogin: true). null bei allen anonymen Übermittlungen. Das vollständige Schema und Verhalten findest du unten unter Identität der Befragten.
Antwortobjekte
Jeder Eintrag im answers-Array steht für die Antwort auf eine einzelne Frage:
| Feld | Typ | Beschreibung |
|---|---|---|
questionId | string | Die MongoDB-ObjectId der Frage |
value | any | Die Antwort der befragten Person (Format je nach Fragetyp unterschiedlich) |
label | string | Nur bei Übermittlungen im Web. Der Titel der Frage als reiner Text, in der Sprache, in der die befragte Person geantwortet hat. |
type | string | Nur bei Übermittlungen im Web. Der Fragetyp, etwa short_text oder matrix. |
subLabels | object | Nur bei Übermittlungen im Web, für eine Frage mit Unterfeldern wie Kontaktdaten, Adresse oder eine Fragengruppe. Ordnet jeder Unterfeld-ID ihre Beschriftung zu. |
valueLabels | object | Bei Übermittlungen im Web und per Telefonanruf, für eine Frage, deren Optionen, Zeilen oder Spalten aus einer Variable kommen. value enthält dann die Werte der Einträge, und diese Zuordnung liefert für jeden gewählten Wert seine Beschriftung. Bei einer Matrix lauten die Schlüssel row:<Wert> und column:<Wert>. Antworten auf feste Listen enthalten es nicht. |
Antworten aus Telefonanrufen enthalten questionId, value und, bei einer Liste aus einer Variable, valueLabels. Web-Antworten können außerdem viewedAt und answeredAt enthalten – wann die Frage angezeigt und wann sie beantwortet wurde, als ISO-8601-Zeitstempel vom Gerät der befragten Person. Mit der Zeit können weitere Felder dazukommen – ignoriere also alle, die du nicht verwendest.
Eine Web-Antwort auf eine Liste aus einer Variable sieht so aus:
{
"questionId": "507f1f77bcf86cd799439099",
"value": "siamese",
"label": "Which breed is your cat?",
"type": "dropdown",
"valueLabels": { "siamese": "Siamese" }
}
Dieselbe Antwort, am Telefon gegeben, kommt ohne label und type an.
Antwortwerte nach Fragetyp
Das value-Feld in jedem Antwortobjekt hängt vom Fragetyp ab. Hier ist das Format für jeden Typ:
Texteingaben
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
short_text | string | "Jane Doe" |
long_text | string | "I really enjoyed the product..." |
email | string | "jane@example.com" |
phone | string | "+1 (555) 123-4567" |
number | number | 42 |
url | string | "https://example.com" |
Auswahlfragen
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
multiple_choice (einfach) | string | "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14" |
multiple_choice (mehrfach) | array<string> | ["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "__other__:Word of mouth"] |
dropdown (einfach) | string | "e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80" |
dropdown (mehrfach) | array<string> | ["e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80", "5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58"] |
yes_no | boolean | true |
value enthält IDs von Optionen, keine Beschriftungen: die id jeder gewählten Option in den choices der Frage. Der Builder erzeugt diese IDs als UUIDs. Die API und der MCP-Server akzeptieren auch eine Option ohne id, etwa { "label": "Search engine" }; in einer Web-Antwort enthält value dann das label dieser Option statt einer ID. multiple_choice und dropdown senden einen einzelnen String – oder ein String-Array, wenn allowMultiple auf true steht. Bildauswahlen (layout: "blocks") sind ebenfalls multiple_choice-Fragen.
Wählt die befragte Person Sonstiges, lautet der Eintrag __other__: gefolgt vom eingegebenen Text, wie im Beispiel oben. Bei einem Telefonanruf wird eine Sonstiges-Antwort mit den eigenen Worten der anrufenden Person gespeichert, ohne das Präfix.
Webhooks senden die Beschriftungen einer festen Liste nicht. Um sie anzuzeigen, gleiche jede ID mit den choices der Frage ab, die Formular abrufen liefert; bei einer Option ohne id enthält value bereits ihr label. Kommen die Optionen aus einer Variable, enthält value die Werte der Einträge, und das valueLabels der Antwort liefert ihre Beschriftungen – siehe Antwortobjekte.
Bewertungsfragen
| Fragetyp | Wertetyp | Beispiel | Wertebereich |
|---|---|---|---|
rating | number | 4 | 1 bis steps (Standard 5) |
opinion_scale | number | 7 | min bis max |
nps | number | 9 | 0 bis 10 |
Datum und Uhrzeit
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
date | string | "2025-03-15" |
Das Format des Datums-Strings entspricht der dateFormat-Eigenschaft der Frage (Standard: YYYY-MM-DD).
Rechtliches und Hinweistexte
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
legal | boolean | true |
statement | string | "" (immer leer --- Hinweistexte erfassen keine Daten) |
Ranking
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
ranking | array<string> | ["5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58", "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "71a4c9e0-3b5d-4f82-9c16-d2e8a0b7f345"] |
Das Array enthält die IDs der Optionen in der von der befragten Person gewählten Reihenfolge, vom ersten bis zum letzten Platz; in einer Web-Antwort steht für eine Option, die ohne id gespeichert wurde, stattdessen ihr label. Ordne den IDs ihre Beschriftungen so zu wie bei den Auswahlfragen.
Matrix
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
matrix | object | { "Speed": "Satisfied", "Price": "Neutral" } |
Bei einer Matrix mit festen Zeilen und Spalten ordnet das Objekt jeder Zeilenbeschriftung die gewählte Spaltenbeschriftung zu. Kommen ihre Zeilen oder Spalten aus einer Variable, ordnet es Zeilen-Werten Spalten-Werte zu; die Beschriftungen, die die befragte Person gesehen hat, stehen dann im valueLabels der Antwort, unter den Schlüsseln row:<Wert> und column:<Wert>.
Datei-Upload
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
file_upload | string | "https://storage.nueform.io/uploads/abc123.pdf" |
Der Wert ist die URL der hochgeladenen Datei im NueForm-Speicher.
Unterschrift und Zeichnung
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
signature | string | "data:image/png;base64,iVBOR..." |
drawing | string | "data:image/png;base64,iVBOR..." |
Beide liefern eine base64-codierte PNG-Data-URI des erfassten Bildes.
Aufnahme
| Fragetyp | Wertetyp | Beispiel |
|---|---|---|
recording | string | "https://storage.nueform.io/recordings/abc123.webm" |
Der Wert ist die URL der hochgeladenen Aufnahmedatei.
Zusammengesetzte Fragen
Zusammengesetzte Fragetypen (contact_info, address, question_group, multi_question_page) erzeugen einen einzigen Antworteintrag, unter der eigenen questionId der zusammengesetzten Frage. Sein value ist ein Objekt mit einem Schlüssel pro Unterfeld-ID. Kontaktdaten und Adresse verwenden eingebaute IDs wie first_name und zip_code; eine Fragengruppe oder eine Seite mit mehreren Fragen verwendet die ID jeder Frage, die sie enthält. Der Wert jedes Unterfelds hat das Format seines eigenen Fragetyps. Web-Antworten enthalten außerdem subLabels, das jeder Unterfeld-ID ihre Beschriftung zuordnet.
Eine contact_info-Frage erzeugt zum Beispiel:
{
"questionId": "507f1f77bcf86cd7994390aa",
"value": {
"first_name": "Jane",
"last_name": "Doe",
"phone_number": "+1 555-0100",
"email": "jane@example.com",
"company": "Acme Inc."
},
"label": "How can we reach you?",
"type": "contact_info",
"subLabels": {
"first_name": "First Name",
"last_name": "Last Name",
"phone_number": "Phone Number",
"email": "Email",
"company": "Company"
}
}
Dieselbe Antwort, am Telefon gegeben, hat denselben value, kommt aber ohne label, type und subLabels an.
Identität der Befragten
Wenn ein Formular mit requireLogin: true konfiguriert ist, ist jede angenommene Übermittlung an einen angemeldeten Benutzer gebunden. Webhook-Payloads legen diese Identität den Formularbesitzern über das respondent-Feld offen. Bei allen anderen Übermittlungen ist das Feld null.
Schema
{
"respondent": {
"id": "507f1f77bcf86cd799439016",
"name": "Jane Smith",
"email": "jane@example.com",
"auth_method": "sso"
}
}
| Feld | Typ | Beschreibung |
|---|---|---|
id | string | Die Benutzer-ID der befragten Person. |
name | string | Anzeigename des Kontos der befragten Person. |
email | string | E-Mail-Adresse des Kontos der befragten Person. |
auth_method | string | Entweder "sso" oder "login". "sso" bedeutet, die befragte Person ist per Single Sign-On Mitglied des Formular-Teams; "login" steht für jede andere unterstützte Authentifizierungsmethode. |
Wann respondent befüllt ist
respondent ist nur befüllt, wenn:
- das Formular
requireLoginauftruegesetzt hat, und - die übermittelnde Person sich vor dem Absenden angemeldet hat, weil das Formular es verlangte.
Wenn zusätzlich requireSsoLogin auf true steht, erreichen nur Benutzer den Absende-Schritt, die per SSO Mitglied des Formular-Teams sind — jedes befüllte respondent-Objekt hat dann auth_method: "sso".
Wann respondent null ist
Das Feld ist für berechenbares Parsen immer im JSON vorhanden und ist null, sobald einer dieser Punkte zutrifft:
- Das Formular erforderte keinen Login (
requireLoginwarfalse). - Die übermittelnde Person war anonym.
- Die Response wurde über den Einwilligungs-Flow nach dem Absenden gespeichert (die Aufforderung „Diese Antwort übernehmen"). Per Einwilligung gespeicherte Responses erscheinen in Webhook-Payloads niemals mit Identität — sie werden nur in der „Meine Antworten"-Ansicht der Person gespeichert und nicht an Webhook-Empfänger weitergegeben.
Webhook-Payloads legen die Identität nur für Befragte offen, die sich angemeldet haben, weil das Formular es verlangte. Identitäten aus der Einwilligung nach dem Absenden werden Webhooks bewusst vorenthalten, um die Grenze zwischen der Privatsphäre der Befragten und den Einblicken der Formularbesitzer zu wahren.
Quiz-Ergebnisse
Bei Formularen in einem Quiz-Modus (knowledge_quiz, lead_qualification oder match_quiz) enthält die gespeicherte Response ein quizResults-Objekt. Dieses Objekt ist nicht direkt in der Webhook-Payload enthalten, du kannst es aber über die Responses-API mit der responseId aus dem Webhook abrufen.
Das quizResults-Objekt hat folgende Struktur:
{
"formMode": "knowledge_quiz",
"score": 7,
"correctAnswers": 7,
"totalScorableQuestions": 10,
"maxScore": 10,
"matchedEndingId": "507f1f77bcf86cd799439099"
}
| Feld | Typ | Beschreibung |
|---|---|---|
formMode | string | Der Quiz-Modus: knowledge_quiz, lead_qualification oder match_quiz |
score | number | Die Gesamtpunktzahl der befragten Person |
correctAnswers | number | Anzahl der richtig beantworteten Fragen (nur Wissensquiz; 0 bei anderen Modi) |
totalScorableQuestions | number | Gesamtzahl der Fragen, die in die Punktzahl einfließen |
maxScore | number | Die maximal erreichbare Punktzahl |
matchedEndingId | string oder undefined | Die ID des Endscreens, der der befragten Person basierend auf ihrer Punktzahl angezeigt wurde |
endingTallies | object oder undefined | Nur Match-Quiz: ordnet jeder Endscreen-ID ihren Zählerstand zu |
Metadaten
Die gespeicherte Response kann außerdem ein metadata-Objekt mit versteckten Feldern enthalten, die über URL-Parameter übergeben wurden. Diese sind über die Responses-API verfügbar, aber nicht Teil der Webhook-Payload.
{
"hiddenFields": {
"utm_source": "google",
"utm_campaign": "spring_sale",
"user_id": "ext_12345"
}
}
Um die Metadaten einer per Webhook zugestellten Response abzurufen, hole sie über die responseId:
curl https://app.nueform.io/api/v1/forms/FORM_ID/responses/RESPONSE_ID \
-H "Authorization: Bearer nf_your_api_key"
HTTP-Header
Jede Webhook-Anfrage enthält diese HTTP-Header:
| Header | Wert |
|---|---|
Content-Type | application/json |
X-NueForm-Signature | HMAC-SHA256-Hex-Digest des rohen Anfrage-Bodys |
Wie du die Signatur validierst, erfährst du unter Verifizierung.
Payload-Größe
Webhook-Payloads sind in der Regel klein (unter 10 KB). Die Größe hängt vor allem von der Anzahl der Fragen und der Länge der Textantworten ab. Datei-Upload-Antworten enthalten URLs (keine Dateiinhalte) und vergrößern die Payload daher kaum.
Nächste Schritte
- Verifizierung --- Webhook-Signaturen validieren
- Testen --- Webhook-Payloads lokal testen
- Ereignisse --- Ereignistypen und Zustellgarantien