Toda requisição de webhook do NueForm envia um payload JSON no corpo da requisição. Esta página documenta o schema completo do payload para cada tipo de evento.
Estrutura comum
Todos os payloads de webhook compartilham estes campos de nível superior:
| Campo | Tipo | Descrição |
|---|---|---|
event | string | O tipo do evento (por exemplo, form.submitted) |
formId | string | O ID único do formulário |
formTitle | string | O título do formulário no momento do envio |
responseId | string | O ID único da resposta |
answers | array | Array de objetos de resposta |
respondent | object ou null | Identidade do respondente logado, quando o formulário exigia login. null para envios anônimos. Veja Identidade do respondente. |
submittedAt | string | Timestamp ISO 8601 de quando o evento foi despachado |
Payload de form.submitted
Este é o payload enviado quando um respondente envia uma resposta completa de formulário.
Exemplo completo
{
"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"
}
Referência de campos
Campos de nível superior
event --- string
Sempre "form.submitted" para este tipo de evento.
formId --- string
O ObjectId do MongoDB do formulário. É uma string hexadecimal de 24 caracteres.
formTitle --- string
O título legível do formulário no momento em que o webhook dispara. Observe que, se você renomear o formulário depois, os webhooks já entregues continuarão contendo o título antigo.
responseId --- string
O ObjectId do MongoDB da resposta armazenada. Você pode usá-lo para buscar a resposta completa pela API de Respostas ou como chave de idempotência para desduplicar entregas de webhook.
submittedAt --- string
Timestamp ISO 8601 indicando quando o webhook foi despachado. Ele é gerado no momento do despacho e será muito próximo (mas não necessariamente idêntico) ao campo submittedAt da resposta no banco de dados.
respondent --- object ou null
Identidade do usuário logado que enviou a resposta, exposta apenas quando o formulário exigia login (requireLogin: true). null para todos os envios anônimos. Veja Identidade do respondente abaixo para o schema completo e o comportamento.
Objetos de resposta
Cada entrada no array answers representa a resposta de uma única pergunta:
| Campo | Tipo | Descrição |
|---|---|---|
questionId | string | O ObjectId do MongoDB da pergunta |
value | any | A resposta do respondente (o formato varia conforme o tipo de pergunta) |
label | string | Só em envios pela web. O título da pergunta como texto simples, no idioma em que o respondente respondeu. |
type | string | Só em envios pela web. O tipo de pergunta, como short_text ou matrix. |
subLabels | object | Só em envios pela web, para uma pergunta com subcampos, como Informações de contato, Endereço ou um Grupo de perguntas. Associa o ID de cada subcampo ao rótulo dele. |
valueLabels | object | Em envios pela web e por ligação telefônica, para uma pergunta cujas opções, linhas ou colunas vêm de uma variável. Nesse caso, value guarda valores de itens, e este mapa dá o rótulo de cada valor escolhido. Em uma Matriz, as chaves são row:<valor> e column:<valor>. Respostas a listas fixas não trazem esse campo. |
Respostas de ligações telefônicas trazem questionId, value e, para uma lista tirada de uma variável, valueLabels. Respostas pela web também podem trazer viewedAt e answeredAt: quando a pergunta foi exibida e quando foi respondida, como carimbos de data e hora ISO 8601 do dispositivo do respondente. Novos campos podem ser adicionados com o tempo, então ignore os que você não usa.
Uma resposta pela web a uma lista carregada de uma variável fica assim:
{
"questionId": "507f1f77bcf86cd799439099",
"value": "siamese",
"label": "Which breed is your cat?",
"type": "dropdown",
"valueLabels": { "siamese": "Siamese" }
}
A mesma resposta dada em uma ligação telefônica chega sem label e type.
Valores de resposta por tipo de pergunta
O campo value de cada objeto de resposta varia de acordo com o tipo de pergunta. Este é o formato para cada tipo:
Entradas de texto
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
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" |
Perguntas de escolha
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
multiple_choice (única) | string | "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14" |
multiple_choice (múltipla) | array<string> | ["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "__other__:Word of mouth"] |
dropdown (única) | string | "e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80" |
dropdown (múltipla) | array<string> | ["e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80", "5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58"] |
yes_no | boolean | true |
value guarda IDs de opção, não rótulos: o id de cada opção escolhida nas choices da pergunta. O construtor cria esses IDs como UUIDs. A API e o servidor MCP também aceitam uma opção sem id, como { "label": "Search engine" }; em uma resposta pela web, value guarda então o label dessa opção no lugar de um ID. multiple_choice e dropdown enviam uma única string, ou um array de strings quando allowMultiple é true. Opções com imagem (layout: "blocks") também são perguntas multiple_choice.
Se o respondente escolher Outro, a entrada é __other__: seguido do texto que ele digitou, como no exemplo acima. Uma ligação telefônica salva uma resposta Outro com as próprias palavras de quem ligou, sem o prefixo.
Os webhooks não enviam os rótulos de uma lista fixa. Para exibi-los, procure cada ID nas choices da pergunta, que Obter Formulário retorna; para uma opção sem id, value já guarda o label dela. Quando as opções vêm de uma variável, value guarda valores de itens e o valueLabels da resposta dá os rótulos deles — veja Objetos de resposta.
Perguntas de avaliação
| Tipo de pergunta | Tipo do valor | Exemplo | Intervalo |
|---|---|---|---|
rating | number | 4 | 1 a steps (padrão 5) |
opinion_scale | number | 7 | min a max |
nps | number | 9 | 0 a 10 |
Data e hora
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
date | string | "2025-03-15" |
O formato da string de data corresponde à propriedade dateFormat configurada na pergunta (o padrão é YYYY-MM-DD).
Legal e declarações
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
legal | boolean | true |
statement | string | "" (sempre vazio --- declarações não coletam dados) |
Ranking
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
ranking | array<string> | ["5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58", "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "71a4c9e0-3b5d-4f82-9c16-d2e8a0b7f345"] |
O array guarda os IDs de opção na ordem escolhida pelo respondente, do primeiro ao último; em uma resposta pela web, uma opção salva sem id aparece pelo seu label no lugar de um ID. Associe os IDs aos rótulos da mesma forma que nas Perguntas de escolha.
Matriz
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
matrix | object | { "Speed": "Satisfied", "Price": "Neutral" } |
Em uma Matriz com linhas e colunas fixas, o objeto mapeia o rótulo de cada linha para o rótulo da coluna selecionada. Quando as linhas ou colunas vêm de uma variável, ele mapeia valores de linha para valores de coluna, e os rótulos que o respondente viu ficam no valueLabels da resposta, nas chaves row:<valor> e column:<valor>.
Upload de arquivo
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
file_upload | string | "https://storage.nueform.io/uploads/abc123.pdf" |
O valor é a URL do arquivo enviado no armazenamento do NueForm.
Assinatura e desenho
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
signature | string | "data:image/png;base64,iVBOR..." |
drawing | string | "data:image/png;base64,iVBOR..." |
Ambos retornam um data URI PNG codificado em base64 da imagem capturada.
Gravação
| Tipo de pergunta | Tipo do valor | Exemplo |
|---|---|---|
recording | string | "https://storage.nueform.io/recordings/abc123.webm" |
O valor é a URL do arquivo de gravação enviado.
Perguntas compostas
Tipos de pergunta compostos (contact_info, address, question_group, multi_question_page) produzem uma única entrada de resposta, com o próprio questionId da pergunta composta. O value dela é um objeto com uma chave por ID de subcampo. Informações de contato e Endereço usam IDs predefinidos, como first_name e zip_code; um Grupo de perguntas ou uma Página com várias perguntas usa o ID de cada pergunta que contém. O valor de cada subcampo segue o formato do próprio tipo de pergunta. Respostas pela web também trazem subLabels, que associa o ID de cada subcampo ao rótulo dele.
Por exemplo, uma pergunta contact_info produz:
{
"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"
}
}
A mesma resposta dada em uma ligação telefônica tem o mesmo value, sem label, type e subLabels.
Identidade do respondente
Quando um formulário é configurado com requireLogin: true, todo envio aceito fica vinculado a um usuário autenticado. Os payloads de webhook expõem essa identidade aos donos do formulário através do campo respondent. Para todos os outros envios, o campo é null.
Schema
{
"respondent": {
"id": "507f1f77bcf86cd799439016",
"name": "Jane Smith",
"email": "jane@example.com",
"auth_method": "sso"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
id | string | O ID de usuário do respondente. |
name | string | Nome de exibição na conta do respondente. |
email | string | Endereço de e-mail na conta do respondente. |
auth_method | string | "sso" ou "login". "sso" indica que o respondente é membro da equipe do formulário via Single Sign-On; "login" indica qualquer outro método de autenticação compatível. |
Quando respondent é preenchido
respondent é preenchido apenas quando:
- O formulário tem
requireLogindefinido comotrue, e - Quem enviou fez login porque o formulário exigia antes de enviar.
Quando requireSsoLogin também é true, apenas usuários que são membros da equipe do formulário via SSO conseguem chegar à etapa de envio, então todo respondent preenchido terá auth_method: "sso".
Quando respondent é null
O campo está sempre presente no JSON para um parsing previsível no destino, e é null sempre que qualquer uma destas condições for verdadeira:
- O formulário não exigia login (
requireLoginerafalse). - Quem enviou era anônimo.
- A resposta foi salva pelo fluxo de consentimento pós-envio (o prompt de "claim this response"). Respostas salvas por consentimento nunca aparecem nos payloads de webhook com identidade anexada — elas são armazenadas apenas na visualização "My Responses" do usuário e não são expostas aos receptores de webhook.
Os payloads de webhook só expõem a identidade de respondentes que fizeram login porque o formulário exigia. Identidades coletadas via consentimento pós-envio são intencionalmente omitidas dos webhooks para respeitar o limite entre a privacidade do respondente e a visibilidade do dono do formulário.
Resultados de questionário
Para formulários em modo de questionário (knowledge_quiz, lead_qualification ou match_quiz), a resposta armazenada inclui um objeto quizResults. Embora esse objeto não seja incluído diretamente no payload do webhook, você pode obtê-lo pela API de Respostas usando o responseId do webhook.
O objeto quizResults tem a seguinte estrutura:
{
"formMode": "knowledge_quiz",
"score": 7,
"correctAnswers": 7,
"totalScorableQuestions": 10,
"maxScore": 10,
"matchedEndingId": "507f1f77bcf86cd799439099"
}
| Campo | Tipo | Descrição |
|---|---|---|
formMode | string | O modo do questionário: knowledge_quiz, lead_qualification ou match_quiz |
score | number | A pontuação total do respondente |
correctAnswers | number | Número de perguntas respondidas corretamente (apenas questionário de conhecimento; 0 para os outros modos) |
totalScorableQuestions | number | Número total de perguntas que contribuem para a pontuação |
maxScore | number | A pontuação máxima possível |
matchedEndingId | string ou undefined | O ID da tela final mostrada ao respondente com base na pontuação |
endingTallies | object ou undefined | Apenas questionário de compatibilidade: mapeia cada ID de tela final para sua contagem |
Metadados
A resposta armazenada também pode incluir um objeto metadata contendo campos ocultos passados via parâmetros de URL. Ele está disponível pela API de Respostas, mas não é incluído no payload do webhook.
{
"hiddenFields": {
"utm_source": "google",
"utm_campaign": "spring_sale",
"user_id": "ext_12345"
}
}
Para acessar os metadados de uma resposta entregue via webhook, busque-a usando o responseId:
curl https://app.nueform.io/api/v1/forms/FORM_ID/responses/RESPONSE_ID \
-H "Authorization: Bearer nf_your_api_key"
Cabeçalhos HTTP
Toda requisição de webhook inclui estes cabeçalhos HTTP:
| Cabeçalho | Valor |
|---|---|
Content-Type | application/json |
X-NueForm-Signature | Digest hexadecimal HMAC-SHA256 do corpo bruto da requisição |
Consulte Verificação para saber como validar a assinatura.
Tamanho do payload
Os payloads de webhook costumam ser pequenos (menos de 10 KB). O tamanho depende principalmente do número de perguntas e do comprimento das respostas de texto. Respostas de upload de arquivo contêm URLs (não o conteúdo dos arquivos), então não aumentam significativamente o tamanho do payload.
Próximos passos
- Verificação --- Valide assinaturas de webhook
- Testes --- Teste payloads de webhook localmente
- Eventos --- Tipos de evento e garantias de entrega