Webhooks
Configure notificaciones de eventos en tiempo real
Webhooks
Un webhook es la entrega de datos a un endpoint cuando ocurre un evento. En nuestro caso, ese evento es el envío de una respuesta a una encuesta. Los webhooks están destinados a usuarios avanzados con conocimientos de programación.
Cómo conectar
Para configurar los webhooks, vaya a la pestaña Integraciones → Webhooks y haga clic en Conectar.
Descargue la versión en markdown de la sección "Webhooks" para usarla en ChatGPT u otros LLMs:
Interfaz de configuración de webhooks
Paso 1: Ir a integraciones
Para configurar los webhooks, vaya a la pestaña Integraciones → Webhooks y haga clic en Conectar.
Paso 2: Formulario de configuración del webhook
Se abrirá una pantalla donde deberá introducir el nombre del webhook, la URL de callback y el tipo de solicitud.
Paso 3: Probar el webhook
Puede probar el webhook usando https://webhook.site
Paso 4: Ver registros
O consultando los registros en la interfaz de SurveyNinja.
Configuración del webhook
El formulario de configuración del webhook tiene los siguientes parámetros:
| Parámetro | Descripción |
|---|---|
| Nombre | Un nombre personalizado para identificar el webhook en la lista |
| URL | La URL de su endpoint. SurveyNinja envía una solicitud POST por cada nueva respuesta a la encuesta |
| Cabeceras | Cabeceras HTTP personalizadas en formato "clave: valor". Se envían con cada solicitud y se duplican en el campo headers del cuerpo del payload para facilitar el registro |
| Habilitado | Interruptor de actividad. Un webhook deshabilitado no envía solicitudes pero conserva toda la configuración |
Token secreto mediante cabecera
Añada una cabecera Authorization: Bearer su-secreto — su servidor podrá verificar que la solicitud proviene auténticamente de SurveyNinja.
Cuándo se activan los webhooks
En SurveyNinja, los webhooks se activan cuando se envía una respuesta a una encuesta. Este es el principal evento que puede rastrear.
Evento: Respuesta a encuesta
El webhook se activa cada vez que un encuestado envía una respuesta a su encuesta, proporcionando notificaciones en tiempo real de nuevas respuestas.
Entrega automática
El webhook se envía automáticamente tan pronto como se recibe una respuesta a la encuesta
Formato del payload
SurveyNinja envía una solicitud POST con un cuerpo JSON. La estructura completa del cuerpo de la solicitud se describe a continuación.
Campos raíz del payload
| Campo | Tipo | Descripción |
|---|---|---|
| headers | object | Cabeceras configuradas en el webhook. Duplicadas en el cuerpo para facilitar el registro y la depuración |
| extra_params | object / array | Variables ocultas y etiquetas UTM enviadas durante la encuesta. Array vacío [] si no hay variables |
| promo_code | string / null | Código promocional utilizado durante la encuesta, o null |
| log_id | int | ID del registro de entrega de este webhook |
| score_all | int | Puntuación máxima posible para toda la encuesta. 0 si la puntuación no está configurada |
| score_earned | int | Puntuación total obtenida por el encuestado |
| score_percent | float / null | Porcentaje del resultado: (score_earned / score_all) × 100, redondeado a 1 decimal. null si score_all = 0 |
| scores | object | Resumen de puntuación: campos user, max y by_question — un mapa { "uuid": int | null } |
| {question_uuid} | object | Respuesta a la pregunta con este UUID. Cada pregunta de la encuesta tiene una clave de nivel superior independiente |
Campos del objeto de pregunta
Cada pregunta en el payload es un objeto identificado por el UUID de la pregunta. Todos los tipos de preguntas comparten los siguientes campos comunes:
| Campo | Tipo | Descripción |
|---|---|---|
| title | string | Texto de la pregunta (título del widget) |
| type | string | Tipo de widget: choiceSingle, choiceMultiple, rating, matrix y otros. |
| question_uuid / uuid | string | UUID de la pregunta (duplicado dentro del objeto) |
| results | object / array | Respuesta del encuestado. El formato depende del tipo de widget — véase la sección a continuación |
| score_count | int / null | Puntuación obtenida para esta pregunta. null si la puntuación no aplica a este tipo |
| score_max | int / null | Puntuación máxima para esta pregunta. null si la puntuación no aplica |
| is_correct_question | bool / null | Corrección general de la respuesta: true — correcta, false — incorrecta, null — no aplicable |
| other | string | Texto de la opción 'Otro', si fue seleccionada (para widgets de selección). Cadena vacía si no fue seleccionada |
| inline_group_id | string / null | UUID del grupo de preguntas, si la pregunta pertenece a un grupo |
| inline_group_title | string / null | Nombre del grupo de preguntas |
| is_inline_group_child | bool | true si la pregunta está dentro de un grupo |
Formato de results por tipo de widget
El campo results tiene un formato diferente según el tipo de pregunta.
choiceSingle, choiceMultiple, yesno, dropdown
Array de opciones seleccionadas. Cada elemento contiene el texto de la opción, la puntuación y el indicador de corrección.
{ "results": [ { "result": "Option A", "score": 10, "is_correct": true } ] } choiceMedia
Array de opciones de medios seleccionadas. El campo result contiene la URL de la imagen de la opción seleccionada.
{ "results": [ { "result": "https://app.surveyninja.io/.../image.png", "score": 3, "is_correct": false } ] } ranking
Array de opciones en el orden establecido por el usuario (primer elemento = clasificado 1.°). La puntuación y la corrección no se aplican 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 (no array). Campo is_star: true — modo estrellas/corazones; score_num: false — modo de visualización no numérica.
{ "results": { "result": "4", "is_star": true, "score": 0, "score_num": false, "is_correct": false } } scale
Objeto con el valor de escala seleccionado, la puntuación y la corrección.
{ "results": { "result": "6", "score": 0, "is_correct": true } } slider
Objeto solo con el valor. La puntuación no aplica a los sliders.
{ "results": { "result": "45" } } input, email, phone
Objeto con el valor introducido. La puntuación no aplica. Para entradas multilínea, los saltos de línea se conservan.
{ "results": { "result": "User's answer text" } } datetime
Objeto con un valor de fecha/hora. El formato del valor depende del modo del 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 archivos subidos. Cada elemento contiene una URL de descarga y la extensión del archivo.
{ "results": [ { "result": "https://app.surveyninja.io/.../document.pdf", "file_ext": "pdf" } ] } matrix
El tipo más complejo. Contiene dos representaciones: results — vista legible por humanos: objeto anidado { "fila": { "columna": { result, score, is_correct } } }. Valor result: "1" — celda marcada, result: "" — vacía. answers — vista 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 } Ejemplo completo del payload
Un ejemplo real del cuerpo de una solicitud webhook con puntuación, múltiples tipos de preguntas y cabeceras personalizadas. Los UUID se han acortado para mayor legibilidad.
{ "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 } } Compatibilidad con versiones anteriores
Los campos de puntuación (score_max, is_correct_question, is_correct dentro de results) se añaden sobre el formato base. Los campos existentes no se eliminan ni se renombran.
Probar webhooks
Puede utilizar las siguientes herramientas para probar los webhooks:
webhook.site
Servicio recomendado para probar webhooks
https://webhook.site Visite el sitio, obtenga una URL única y úsela para probar sus webhooks.
Ver registros
Puede verificar el funcionamiento del webhook a través de los registros
La interfaz de SurveyNinja proporciona registros de entrega de webhooks para rastrear su funcionamiento.
Seguridad
Para la seguridad de los webhooks, se recomienda usar HTTPS y verificar la autenticidad de las solicitudes.
Recomendaciones de seguridad
- Use HTTPS para la URL de callback
- Verifique las firmas de las solicitudes para confirmar su autenticidad
- Restrinja el acceso al endpoint únicamente a las direcciones IP de SurveyNinja
- Implemente tiempos de espera para el procesamiento de webhooks