Webhooks
Configure notificações de eventos em tempo real
Webhooks
Um webhook é a entrega de dados a um endpoint quando um evento ocorre. No nosso caso, esse evento é o envio de uma resposta a uma pesquisa. Os webhooks são destinados a usuários avançados com conhecimento de programação.
Como conectar
Para configurar webhooks, acesse a aba Integrações → Webhooks e clique em Conectar.
Baixe a versão em markdown da seção "Webhooks" para usar no ChatGPT ou outros LLMs:
Interface de configuração de webhooks
Passo 1: Acessar integrações
Para configurar webhooks, acesse a aba Integrações → Webhooks e clique em Conectar.
Passo 2: Formulário de configuração do webhook
Uma tela será aberta onde você deverá inserir o nome do webhook, a URL de callback e o tipo de requisição.
Passo 3: Testar o webhook
Você pode testar o webhook usando https://webhook.site
Passo 4: Visualizar registros
Ou visualizando os registros na interface do SurveyNinja.
Configurações do webhook
O formulário de configuração do webhook possui os seguintes parâmetros:
| Parâmetro | Descrição |
|---|---|
| Nome | Um nome personalizado para identificar o webhook na lista |
| URL | A URL do seu endpoint. O SurveyNinja envia uma requisição POST para ela a cada nova resposta de pesquisa |
| Cabeçalhos | Cabeçalhos HTTP personalizados no formato "chave: valor". Enviados com cada requisição e duplicados no campo headers do corpo do payload para facilitar o registro |
| Habilitado | Alternância de atividade. Um webhook desabilitado não envia requisições, mas mantém todas as configurações |
Token secreto via cabeçalho
Adicione um cabeçalho Authorization: Bearer seu-segredo — seu servidor poderá verificar que a requisição veio genuinamente do SurveyNinja.
Quando os webhooks são disparados
No SurveyNinja, os webhooks são disparados quando uma resposta de pesquisa é enviada. Este é o principal evento que você pode rastrear.
Evento: Resposta de pesquisa
O webhook é disparado toda vez que um respondente envia uma resposta à sua pesquisa, fornecendo notificações em tempo real de novas respostas.
Entrega automática
O webhook é enviado automaticamente assim que uma resposta de pesquisa é recebida
Formato do payload
O SurveyNinja envia uma requisição POST com um corpo JSON. A estrutura completa do corpo da requisição está descrita abaixo.
Campos raiz do payload
| Campo | Tipo | Descrição |
|---|---|---|
| headers | object | Cabeçalhos configurados no webhook. Duplicados no corpo para facilitar o registro e a depuração |
| extra_params | object / array | Variáveis ocultas e tags UTM enviadas durante a pesquisa. Array vazio [] se não houver variáveis |
| promo_code | string / null | Código promocional usado durante a pesquisa, ou null |
| log_id | int | ID do registro de entrega deste webhook |
| score_all | int | Pontuação máxima possível para toda a pesquisa. 0 se a pontuação não estiver configurada |
| score_earned | int | Pontuação total obtida pelo respondente |
| score_percent | float / null | Percentual do resultado: (score_earned / score_all) × 100, arredondado para 1 casa decimal. null se score_all = 0 |
| scores | object | Resumo de pontuação: campos user, max e by_question — um mapa { "uuid": int | null } |
| {question_uuid} | object | Resposta à pergunta com este UUID. Cada pergunta da pesquisa tem uma chave de nível superior separada |
Campos do objeto de pergunta
Cada pergunta no payload é um objeto identificado pelo UUID da pergunta. Todos os tipos de perguntas compartilham os seguintes campos comuns:
| Campo | Tipo | Descrição |
|---|---|---|
| title | string | Texto da pergunta (título do widget) |
| type | string | Tipo de widget: choiceSingle, choiceMultiple, rating, matrix e outros. |
| question_uuid / uuid | string | UUID da pergunta (duplicado dentro do objeto) |
| results | object / array | Resposta do respondente. O formato depende do tipo de widget — veja a seção abaixo |
| score_count | int / null | Pontuação obtida para esta pergunta. null se a pontuação não se aplica a este tipo |
| score_max | int / null | Pontuação máxima para esta pergunta. null se a pontuação não se aplica |
| is_correct_question | bool / null | Correção geral da resposta: true — correta, false — incorreta, null — não aplicável |
| other | string | Texto da opção 'Outro', se selecionada (para widgets de escolha). String vazia se não selecionada |
| inline_group_id | string / null | UUID do grupo de perguntas, se a pergunta pertencer a um grupo |
| inline_group_title | string / null | Nome do grupo de perguntas |
| is_inline_group_child | bool | true se a pergunta estiver dentro de um grupo |
Formato de results por tipo de widget
O campo results tem um formato diferente dependendo do tipo de pergunta.
choiceSingle, choiceMultiple, yesno, dropdown
Array de opções selecionadas. Cada elemento contém o texto da opção, a pontuação e o indicador de correção.
{ "results": [ { "result": "Option A", "score": 10, "is_correct": true } ] } choiceMedia
Array de opções de mídia selecionadas. O campo result contém a URL da imagem da opção selecionada.
{ "results": [ { "result": "https://app.surveyninja.io/.../image.png", "score": 3, "is_correct": false } ] } ranking
Array de opções na ordem definida pelo usuário (primeiro elemento = classificado em 1.°). Pontuação e correção não se aplicam a este tipo.
{ "results": [ { "result": "First place", "score": null, "is_correct": null }, { "result": "Second place", "score": null, "is_correct": null }, { "result": "Third place", "score": null, "is_correct": null } ] } rating
Objeto (não array). Campo is_star: true — modo de estrelas/corações; score_num: false — modo de exibição não numérica.
{ "results": { "result": "4", "is_star": true, "score": 0, "score_num": false, "is_correct": false } } scale
Objeto com o valor de escala selecionado, a pontuação e a correção.
{ "results": { "result": "6", "score": 0, "is_correct": true } } slider
Objeto apenas com o valor. A pontuação não se aplica a sliders.
{ "results": { "result": "45" } } input, email, phone
Objeto com o valor inserido. A pontuação não se aplica. Para entradas multilinha, as quebras de linha são preservadas.
{ "results": { "result": "User's answer text" } } datetime
Objeto com um valor de data/hora. O formato do valor depende do modo do widget.
// Date + time { "results": { "result": "12.03.2026 21:12" } } // Date only { "results": { "result": "11.03.2026" } } // Time only { "results": { "result": "18:14" } } file
Array de arquivos enviados. Cada elemento contém uma URL de download e a extensão do arquivo.
{ "results": [ { "result": "https://app.surveyninja.io/.../document.pdf", "file_ext": "pdf" } ] } matrix
O tipo mais complexo. Contém duas representações: results — visão legível por humanos: objeto aninhado { "linha": { "coluna": { result, score, is_correct } } }. Valor result: "1" — célula marcada, result: "" — vazia. answers — visão por UUID para máquinas: { "row_uuid": { "col_uuid": true | false } }
{ "results": { "Pasta": { "Bad": { "result": "1", "score": 2, "is_correct": false }, "OK": { "result": "", "score": null, "is_correct": false }, "Good": { "result": "", "score": null, "is_correct": true } }, "Potatoes": { "Bad": { "result": "1", "score": 2, "is_correct": true }, "OK": { "result": "", "score": null, "is_correct": true }, "Good": { "result": "", "score": null, "is_correct": false } } }, "answers": { "row-uuid-1": { "col-uuid-1": true, "col-uuid-2": false, "col-uuid-3": false }, "row-uuid-2": { "col-uuid-1": true, "col-uuid-2": false, "col-uuid-3": false } }, "is_bool": true } Exemplo completo do payload
Um exemplo real do corpo de uma requisição webhook com pontuação, múltiplos tipos de perguntas e cabeçalhos personalizados. Os UUIDs foram abreviados para facilitar a leitura.
{ "headers": { "Authorization": "Bearer my-secret-token", "X-Source": "surveyninja" }, "extra_params": { "utm_source": "email", "utm_campaign": "spring2024" }, "promo_code": null, "log_id": 1916713, "score_all": 52, "score_earned": 29, "score_percent": 55.8, "scores": { "user": 29, "max": 52, "by_question": { "uuid-choice-1": 0, "uuid-choice-2": 3, "uuid-rating-1": 0, "uuid-scale-1": 0, "uuid-matrix-1": 6 } }, "uuid-choice-1": { "title": "Select one option", "type": "choiceSingle", "question_uuid": "uuid-choice-1", "uuid": "uuid-choice-1", "results": [ { "result": "Option B", "score": 0, "is_correct": false } ], "score_count": 0, "score_max": 4, "is_correct_question": false, "other": "", "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-choice-2": { "title": "Check all that apply", "type": "choiceMultiple", "question_uuid": "uuid-choice-2", "uuid": "uuid-choice-2", "results": [ { "result": "Option A", "score": 3, "is_correct": true } ], "score_count": 3, "score_max": 3, "is_correct_question": true, "other": "", "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-rating-1": { "title": "Rate the service", "type": "rating", "question_uuid": "uuid-rating-1", "uuid": "uuid-rating-1", "results": { "result": "4", "is_star": true, "score": 0, "score_num": false, "is_correct": false }, "score_count": 0, "score_max": 2, "is_correct_question": false, "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-scale-1": { "title": "On a scale of 1 to 10", "type": "scale", "question_uuid": "uuid-scale-1", "uuid": "uuid-scale-1", "results": { "result": "6", "score": 0, "is_correct": true }, "score_count": 0, "score_max": 3, "is_correct_question": true, "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-input-1": { "title": "Leave a comment", "type": "input", "question_uuid": "uuid-input-1", "uuid": "uuid-input-1", "results": { "result": "Everything is great!" }, "score_count": null, "score_max": null, "is_correct_question": null, "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-file-1": { "title": "Attach a file", "type": "file", "question_uuid": "uuid-file-1", "uuid": "uuid-file-1", "results": [ { "result": "https://app.surveyninja.io/.../document.pdf", "file_ext": "pdf" } ], "score_count": null, "score_max": null, "is_correct_question": null, "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false }, "uuid-matrix-1": { "title": "Rate the dishes", "type": "matrix", "question_uuid": "uuid-matrix-1", "uuid": "uuid-matrix-1", "results": { "Pasta": { "Bad": { "result": "1", "score": 2, "is_correct": false }, "Good": { "result": "", "score": null, "is_correct": true } }, "Potatoes": { "Bad": { "result": "1", "score": 2, "is_correct": true }, "Good": { "result": "", "score": null, "is_correct": false } } }, "answers": { "row-uuid-1": { "col-uuid-1": true, "col-uuid-2": false }, "row-uuid-2": { "col-uuid-1": true, "col-uuid-2": false } }, "is_bool": true, "score_count": 6, "score_max": 6, "is_correct_question": false, "inline_group_id": null, "inline_group_title": null, "is_inline_group_child": false } } Compatibilidade retroativa
Os campos de pontuação (score_max, is_correct_question, is_correct dentro de results) são adicionados sobre o formato base. Os campos existentes não são removidos nem renomeados.
Testar webhooks
Você pode usar as seguintes ferramentas para testar os webhooks:
webhook.site
Serviço recomendado para testar webhooks
https://webhook.site Acesse o site, obtenha uma URL única e use-a para testar seus webhooks.
Visualizar registros
Você pode verificar o funcionamento do webhook pelos registros
A interface do SurveyNinja fornece registros de entrega de webhooks para rastrear seu funcionamento.
Segurança
Para a segurança dos webhooks, recomenda-se usar HTTPS e verificar a autenticidade das requisições.
Recomendações de segurança
- Use HTTPS para a URL de callback
- Verifique as assinaturas das requisições para confirmar sua autenticidade
- Restrinja o acesso ao endpoint apenas aos endereços IP do SurveyNinja
- Implemente tempos limite para o processamento de webhooks