Every NueForm webhook request sends a JSON payload in the request body. This page documents the complete payload schema for each event type.
Common Structure
All webhook payloads share these top-level fields:
| Field | Type | Description |
|---|---|---|
event | string | The event type (e.g., form.submitted) |
formId | string | The unique ID of the form |
formTitle | string | The title of the form at the time of submission |
responseId | string | The unique ID of the response |
answers | array | Array of answer objects |
respondent | object or null | Identity of the logged-in respondent, when the form required login. null for anonymous submissions. See Respondent Identity. |
submittedAt | string | ISO 8601 timestamp of when the event was dispatched |
form.submitted Payload
This is the payload sent when a respondent submits a complete form response.
Full Example
{
"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"
}
Field Reference
Top-Level Fields
event --- string
Always "form.submitted" for this event type.
formId --- string
The MongoDB ObjectId of the form. This is a 24-character hexadecimal string.
formTitle --- string
The human-readable title of the form at the time the webhook fires. Note that if you rename the form later, previously delivered webhooks will still contain the old title.
responseId --- string
The MongoDB ObjectId of the stored response. You can use this to fetch the full response via the Responses API or as an idempotency key to deduplicate webhook deliveries.
submittedAt --- string
ISO 8601 timestamp indicating when the webhook was dispatched. This is generated at dispatch time and will be very close to (but not necessarily identical to) the response's submittedAt field in the database.
respondent --- object or null
Identity of the logged-in user who submitted the response, surfaced only when the form required login (requireLogin: true). null for all anonymous submissions. See Respondent Identity below for the full schema and behaviour.
Answer Objects
Each entry in the answers array represents a single question's response:
| Field | Type | Description |
|---|---|---|
questionId | string | The MongoDB ObjectId of the question |
value | any | The respondent's answer (format varies by question type) |
label | string | Soumissions sur le web uniquement. Le titre de la question en texte brut, dans la langue dans laquelle le répondant a répondu. |
type | string | Soumissions sur le web uniquement. Le type de question, par exemple short_text ou matrix. |
subLabels | object | Soumissions sur le web uniquement, pour une question à sous-champs, comme Coordonnées, Adresse ou un Groupe de questions. Associe l'ID de chaque sous-champ à son libellé. |
valueLabels | object | Soumissions sur le web et par appel téléphonique, pour une question dont les choix, les lignes ou les colonnes viennent d'une variable. value contient alors des valeurs d'éléments, et cette table donne le libellé de chaque valeur choisie. Sur une Matrice, les clés sont row:<valeur> et column:<valeur>. Les réponses aux listes fixes ne le contiennent pas. |
Les réponses issues d'appels téléphoniques contiennent questionId, value et, pour une liste tirée d'une variable, valueLabels. Les réponses web peuvent aussi contenir viewedAt et answeredAt : le moment où la question a été affichée et celui où elle a reçu une réponse, sous forme d'horodatages ISO 8601 issus de l'appareil du répondant. D'autres champs pourront s'ajouter avec le temps : ignorez ceux dont vous ne vous servez pas.
Une réponse web à une liste chargée depuis une variable ressemble à ceci :
{
"questionId": "507f1f77bcf86cd799439099",
"value": "siamese",
"label": "Which breed is your cat?",
"type": "dropdown",
"valueLabels": { "siamese": "Siamese" }
}
La même réponse donnée lors d'un appel téléphonique arrive sans label ni type.
Answer Values by Question Type
The value field in each answer object varies depending on the question type. Here is the format for each type:
Text Inputs
| Question Type | Value Type | Example |
|---|---|---|
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" |
Choice Questions
| Question Type | Value Type | Example |
|---|---|---|
multiple_choice (single) | string | "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14" |
multiple_choice (multi) | array<string> | ["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "__other__:Word of mouth"] |
dropdown (single) | string | "e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80" |
dropdown (multi) | array<string> | ["e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80", "5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58"] |
yes_no | boolean | true |
value contient des ID de choix, pas des libellés : l'id de chaque choix sélectionné dans les choices de la question. L'éditeur crée ces ID sous forme d'UUID. L'API et le serveur MCP acceptent aussi un choix sans id, comme { "label": "Search engine" } ; dans une réponse web, value contient alors le label de ce choix au lieu d'un ID. multiple_choice et dropdown envoient une seule chaîne, ou un tableau de chaînes quand allowMultiple vaut true. Les choix avec image (layout: "blocks") sont aussi des questions multiple_choice.
Si le répondant choisit Autre, l'entrée est __other__: suivi du texte qu'il a saisi, comme dans l'exemple ci-dessus. Un appel téléphonique enregistre une réponse Autre avec les propres mots de l'appelant, sans le préfixe.
Les webhooks n'envoient pas les libellés d'une liste fixe. Pour les afficher, cherchez chaque ID dans les choices de la question, que renvoie Obtenir un formulaire ; pour un choix sans id, value contient déjà son label. Quand les choix viennent d'une variable, value contient des valeurs d'éléments et le valueLabels de la réponse donne leurs libellés : voir Answer Objects.
Rating Questions
| Question Type | Value Type | Example | Range |
|---|---|---|---|
rating | number | 4 | 1 to steps (default 5) |
opinion_scale | number | 7 | min to max |
nps | number | 9 | 0 to 10 |
Date and Time
| Question Type | Value Type | Example |
|---|---|---|
date | string | "2025-03-15" |
The date string format matches the dateFormat property configured on the question (defaults to YYYY-MM-DD).
Legal and Statements
| Question Type | Value Type | Example |
|---|---|---|
legal | boolean | true |
statement | string | "" (always empty --- statements collect no data) |
Ranking
| Question Type | Value Type | Example |
|---|---|---|
ranking | array<string> | ["5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58", "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "71a4c9e0-3b5d-4f82-9c16-d2e8a0b7f345"] |
Le tableau contient des ID de choix dans l'ordre du répondant, du premier au dernier ; dans une réponse web, un choix enregistré sans id y figure par son label au lieu d'un ID. Associez les ID à leurs libellés comme pour les questions à choix.
Matrix
| Question Type | Value Type | Example |
|---|---|---|
matrix | object | { "Speed": "Satisfied", "Price": "Neutral" } |
Pour une Matrice aux lignes et colonnes fixes, l'objet associe le libellé de chaque ligne au libellé de la colonne choisie. Quand ses lignes ou ses colonnes viennent d'une variable, il associe des valeurs de ligne à des valeurs de colonne, et les libellés vus par le répondant se trouvent dans le valueLabels de la réponse, sous les clés row:<valeur> et column:<valeur>.
File Upload
| Question Type | Value Type | Example |
|---|---|---|
file_upload | string | "https://storage.nueform.io/uploads/abc123.pdf" |
The value is the URL of the uploaded file in NueForm's storage.
Signature and Drawing
| Question Type | Value Type | Example |
|---|---|---|
signature | string | "data:image/png;base64,iVBOR..." |
drawing | string | "data:image/png;base64,iVBOR..." |
Both return a base64-encoded PNG data URI of the captured image.
Recording
| Question Type | Value Type | Example |
|---|---|---|
recording | string | "https://storage.nueform.io/recordings/abc123.webm" |
The value is the URL of the uploaded recording file.
Composite Questions
Les types de questions composites (contact_info, address, question_group, multi_question_page) produisent une seule entrée de réponse, sous le questionId de la question composite elle-même. Son value est un objet dont les clés sont les ID des sous-champs. Coordonnées et Adresse utilisent des ID intégrés comme first_name et zip_code ; pour un Groupe de questions ou une Page multi-questions, ce sont les ID des questions qu'ils contiennent. La valeur de chaque sous-champ suit le format de son propre type de question. Les réponses web contiennent aussi subLabels, qui associe l'ID de chaque sous-champ à son libellé.
Par exemple, une question contact_info produit :
{
"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"
}
}
La même réponse donnée lors d'un appel téléphonique a le même value, sans label, type ni subLabels.
Respondent Identity
When a form is configured with requireLogin: true, every accepted submission is tied to a signed-in user. Webhook payloads expose that identity to form owners through the respondent field. For all other submissions the field is null.
Schema
{
"respondent": {
"id": "507f1f77bcf86cd799439016",
"name": "Jane Smith",
"email": "jane@example.com",
"auth_method": "sso"
}
}
| Field | Type | Description |
|---|---|---|
id | string | The respondent's user ID. |
name | string | Display name on the respondent's account. |
email | string | Email address on the respondent's account. |
auth_method | string | Either "sso" or "login". "sso" indicates the respondent is a member of the form's team via Single Sign-On; "login" indicates any other supported authentication method. |
When respondent is populated
respondent is populated only when:
- The form has
requireLoginset totrue, and - The submitter signed in because the form required it before submitting.
When requireSsoLogin is also true, only users who are members of the form's team via SSO can reach the submit step, so every populated respondent will have auth_method: "sso".
When respondent is null
The field is always present in the JSON for predictable downstream parsing, and is null whenever any of these is true:
- The form did not require login (
requireLoginwasfalse). - The submitter was anonymous.
- The response was saved via the post-submit consent flow (the "claim this response" prompt). Consent-saved responses never appear in webhook payloads with identity attached — they are stored only in the user's "My Responses" view and are not exposed to webhook receivers.
Webhook payloads only expose identity for respondents who logged in because the form required it. Identities collected via post-submit consent are intentionally withheld from webhooks to honor the boundary between a respondent's privacy and an owner's insight.
Quiz Results
For forms running in a quiz mode (knowledge_quiz, lead_qualification, or match_quiz), the stored response includes a quizResults object. While this object is not directly included in the webhook payload, you can retrieve it via the Responses API using the responseId from the webhook.
The quizResults object has the following structure:
{
"formMode": "knowledge_quiz",
"score": 7,
"correctAnswers": 7,
"totalScorableQuestions": 10,
"maxScore": 10,
"matchedEndingId": "507f1f77bcf86cd799439099"
}
| Field | Type | Description |
|---|---|---|
formMode | string | The quiz mode: knowledge_quiz, lead_qualification, or match_quiz |
score | number | The respondent's total score |
correctAnswers | number | Number of questions answered correctly (knowledge quiz only; 0 for other modes) |
totalScorableQuestions | number | Total number of questions that contribute to the score |
maxScore | number | The maximum achievable score |
matchedEndingId | string or undefined | The ID of the end screen shown to the respondent based on their score |
endingTallies | object or undefined | Match quiz only: maps each end screen ID to its tally count |
Metadata
The stored response may also include a metadata object containing hidden fields passed via URL parameters. This is available via the Responses API but is not included in the webhook payload.
{
"hiddenFields": {
"utm_source": "google",
"utm_campaign": "spring_sale",
"user_id": "ext_12345"
}
}
To access metadata for a webhook-delivered response, fetch it using the responseId:
curl https://app.nueform.io/api/v1/forms/FORM_ID/responses/RESPONSE_ID \
-H "Authorization: Bearer nf_your_api_key"
HTTP Headers
Every webhook request includes these HTTP headers:
| Header | Value |
|---|---|
Content-Type | application/json |
X-NueForm-Signature | HMAC-SHA256 hex digest of the raw request body |
See Verification for how to validate the signature.
Payload Size
Webhook payloads are typically small (under 10 KB). The size depends primarily on the number of questions and the length of text answers. File upload answers contain URLs (not file contents), so they do not significantly increase payload size.
Next Steps
- Verification --- Validate webhook signatures
- Testing --- Test webhook payloads locally
- Events --- Event types and delivery guarantees