Idioma: Español
Un paso de webhook envía una solicitud HTTP a un sistema externo cada vez que el flujo lo alcanza. Los webhooks son el puente entre ActivityInfo y otras herramientas: plataformas de flujo de trabajo como Power Automate, Zapier, n8n o Pipedream, herramientas de chat como Google Chat o Slack, o sus propios servicios.
Configuración
| Configuración | Descripción ||---------------|-------------|| Etiqueta | El nombre del paso, que se muestra en el flujo y en el historial de ejecución. | | URL de webhook | La URL a la que se envía la solicitud. Debe ser una URL https://. | | Formato de carga útil | La forma del cuerpo de la solicitud: Compatible con ActivityInfo 4.0, Estándar o Personalizado. | | Secreto de firma digital | Opcional. Cuando se genera, cada solicitud se firma para que el receptor pueda verificarla. Consulte Firma digital. |
Entrega
La solicitud es un POST HTTP con Content-type: application/json. Los tiempos de espera de conexión y lectura son de 15 segundos y no se siguen las redirecciones. Una respuesta con un código de estado 2xx marca el paso como exitoso; cualquier otra respuesta, o un fallo de conexión, hace que se reintente la entrega.
Todas las solicitudes llevan estos encabezados, siguiendo la convención de standard-webhooks:
| Encabezado | Valor ||------------|---------|| webhook-id | Un ID único para el evento, p. ej., msg_cfbin3msbq939jk. Los reintentos del mismo evento llevan el mismo ID, para que los receptores puedan deduplicar. | | webhook-timestamp | La hora de envío, en segundos desde la época (epoch). | | webhook-signature | Presente cuando se ha generado un secreto de firma digital. Consulte Firma digital. |
Firma digital
Generar un secreto de firma digital permite al sistema receptor verificar que una solicitud proviene genuinamente de ActivityInfo y no ha sido alterada. La signatura sigue el esquema simétrico de standard-webhooks:
webhook-signature: v1,<base64 HMAC-SHA256 of "{webhook-id}.{webhook-timestamp}.{body}">
La signatura se calcula sobre los bytes exactos del cuerpo de la solicitud, sea cual sea el formato de la carga útil. El secreto se muestra una sola vez cuando se genera; cópielo en el sistema receptor en ese momento. Cambiar la URL de webhook borra el secreto; guarde primero la nueva URL y luego genere un nuevo secreto para ella.
Formatos de carga útil
Los siguientes ejemplos provienen del mismo evento: se editó un registro en un formulario de Registro de Pacientes, cambiando el campo Estado de "En tratamiento" a "Recuperado". Los campos del formulario llevan códigos (NAME, AGE, STATUS, ...) — recomendamos encarecidamente asignar códigos a sus campos, ya que identifican los campos en las cargas útiles y plantillas de abajo de forma mucho más legible que los ID de campo, y sobreviven a los cambios de etiqueta.
El formulario tiene un campo de cada tipo común: un número de serie (NUMBER), texto (NAME), una cantidad (AGE), una fecha (REGDATE), un mes (MONTH), una semana (WEEK), una selección única (STATUS), una selección multiple (SYMPTOMS), una referencia a un formulario de Clínica (CLINIC), una referencia múltiple (NEARBY), un punto geográfico (LOCATION) y un campo calculado (ADULT).
Compatible con ActivityInfo 4.0
El formato de carga útil exacto de los webhooks de ActivityInfo 4.0, conservado para las integraciones construidas sobre él —incluido el conector de Power Automate. Las automatizaciones migradas desde la versión 4.0 y las conexiones realizadas a través de Power Automate utilizan este formato; los nuevos pasos de webhook utilizan por defecto el formato Estándar. Consulte De los webhooks de ActivityInfo 4.0 a las automatizaciones para más información.
El cuerpo describe el evento: data.update solo lleva los campos modificados por el evento (todos los campos para un registro añadido), mientras que data.previous —presente en ediciones y eliminaciones— es el estado completo almacenado del registro antes del cambio. Los campos se identifican por su código (o ID de campo cuando el campo no tiene código). El type del evento es record.added, record.edited o record.deleted.
Dado que el cuerpo se construye a partir de los valores almacenados del registro, los campos calculados no se incluyen — se computan al leerlos, no se almacenan, por lo que nunca aparecen en este formato. Un consumidor que necesite un valor calculado debe recalcularlo o utilizar el formato Estándar o Personalizado, que evalúan los campos calculados como cualquier otro.
{
"type": "record.edited",
"timestamp": "2026-08-02 13:30:00 +0200",
"id": "cfbin3msbq939jk",
"data": {
"update": {
"formId": "cabwlbemsbq938l5",
"formLabel": "Registro de Pacientes",
"recordId": "cuusah2msbq938xi",
"parent": null,
"deleted": false,
"time": "2026-08-02 13:30:00 +0200",
"fields": {
"STATUS": "Recuperado"
}
},
"previous": {
"formId": "cabwlbemsbq938l5",
"formLabel": "Registro de Pacientes",
"recordId": "cuusah2msbq938xi",
"parent": null,
"time": "2026-07-30 11:00:00 +0200",
"fields": {
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": "En tratamiento",
"SYMPTOMS": ["Fiebre", "Tos"],
"CLINIC": {
"reference": {
"recordId": "cfw5r5dmsbq938vh",
"formId": "cprk1xdmsbq93893"
}
},
"LOCATION": {
"latitude": 0.9432,
"longitude": 29.2154
}
}
},
"user": {
"userName": "Amara Diallo",
"userEmail": "amara.diallo@example.org",
"userId": "ci5dxvbkq1v6ueg2"
}
}
}
Valores de campo en este formato:
| Tipo de campo | Valor ||---------------|---------|| Texto, número de serie, código de barras | Texto | | Cantidad | Número | | Fecha, semana, mes | Texto, p. ej., "2026-07-30", "2026W31", "2026-07" | | Selección única | El código de la opción si lo tiene, si no su etiqueta | | Selección multiple | Matriz de códigos/etiquetas de opción, en el orden de las opciones del formulario | | Referencia | {"reference": {"recordId": ..., "formId": ...}} | | Referencia múltiple | Matriz de cadenas de texto "formId:recordId" | | Punto geográfico | {"latitude": ..., "longitude": ...} | | Datos adjuntos | Matriz de {"filename": ..., "mimetype": ..., "url": ...} con una URL de descarga | | Calculado | No incluido — los campos calculados se computan al leerlos, no se almacenan |
Para una eliminación (record.deleted), update.deleted es true, update.fields está vacío y previous lleva el último estado del registro. Los registros de subformularios llevan un objeto parent con parentRecordId, parentFormId y parentFormLabel en lugar de null.
Estándar
Los datos del paso del desencadenador serializados como JSON — la misma fila única, dispuesta exactamente como la ven las fórmulas. Cada campo del formulario está presente en cada evento (los campos en blanco como null, para que la forma de la carga útil sea estable), identificados por el código del campo (o la etiqueta cuando el campo no tiene código). Las estructuras _previous, _user y _trigger aparecen bajo los mismos nombres reservados que usan las fórmulas.
{
"_id": "cuusah2msbq938xi",
"NUMBER": null,
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": {
"_id": "s2",
"label": "Recuperado"
},
"SYMPTOMS": [
{ "_id": "y1", "label": "Fiebre" },
{ "_id": "y2", "label": "Tos" }
],
"CLINIC": {
"_id": "cfw5r5dmsbq938vh",
"label": "Puesto de Salud de Mangina"
},
"NEARBY": [
{ "_id": "cfw5r5dmsbq938vh", "label": "Puesto de Salud de Mangina" },
{ "_id": "c7ptg4xmsbq938wj", "label": "Hospital de Referencia de Beni" }
],
"LOCATION": {
"LATITUDE": 0.9432,
"LONGITUDE": 29.2154,
"ACCURACY": null
},
"ADULT": true,
"_lastEditTime": "2026-08-02T11:30:00Z",
"_previous": {
"_id": "cuusah2msbq938xi",
"NUMBER": null,
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": {
"_id": "s1",
"label": "En tratamiento"
},
"SYMPTOMS": [
{ "_id": "y1", "label": "Fiebre" },
{ "_id": "y2", "label": "Tos" }
],
"CLINIC": {
"_id": "cfw5r5dmsbq938vh",
"label": "Puesto de Salud de Mangina"
},
"NEARBY": [
{ "_id": "cfw5r5dmsbq938vh", "label": "Puesto de Salud de Mangina" },
{ "_id": "c7ptg4xmsbq938wj", "label": "Hospital de Referencia de Beni" }
],
"LOCATION": {
"LATITUDE": 0.9432,
"LONGITUDE": 29.2154,
"ACCURACY": null
},
"ADULT": true,
"_lastEditTime": "2026-07-30T09:00:00Z"
},
"_user": {
"name": "Amara Diallo",
"email": "amara.diallo@example.org",
"id": "ci5dxvbkq1v6ueg2"
},
"_trigger": {
"type": "RECORD_EDITED",
"time": "2026-08-02T11:30:00Z"
}
}
Valores de campo en este formato:
| Tipo de campo | Valor ||---------------|---------|| Texto, número de serie, código de barras | Texto, null cuando está en blanco | | Cantidad | Número | | Fecha, semana, mes | Texto, p. ej., "2026-07-30", "2026W31", "2026-07" | | Selección única | {"_id": <id de opción>, "label": <etiqueta de opción>} | | Selección multiple | Matriz de objetos {"_id", "label"} | | Referencia | {"_id": <id de registro>, "label": <etiqueta de registro>} — la misma etiqueta legible que tiene el registro en toda la aplicación | | Referencia múltiple | Matriz de objetos {"_id", "label"} | | Punto geográfico | {"LATITUDE", "LONGITUDE", "ACCURACY"} | | Datos adjuntos | Matriz de objetos {"_id", "filename", "mimetype"} | | Calculado | El resultado de la fórmula | | Valores de fecha y hora (_lastEditTime, _trigger.time) | ISO-8601 UTC, p. ej., "2026-08-02T11:30:00Z" |
_previous solo está presente para el desencadenador de edición; las entradas de _user son null para los cambios no atribuibles a un usuario.
Personalizado
Usted mismo escribe el cuerpo de la solicitud, como una plantilla con referencias ${...} — las mismas referencias que utilizan las plantillas del paso de correo electrónico, evaluadas con los datos del paso del desencadenador. Este es el formato que debe utilizar cuando el sistema receptor dicta la forma del cuerpo, como por ejemplo para publicar un mensaje directamente en un espacio de Google Chat:
{"text": "Paciente ${NAME} en ${CLINIC.NAME} ahora está ${STATUS} (antes ${_previous.STATUS}), actualizado por ${_user.name}"}
produce:
{"text": "Paciente Amina Yusuf en Puesto de Salud de Mangina ahora está Recuperado (antes En tratamiento), actualizado por Amara Diallo"}
Una referencia puede ser un código de campo, una navegación a través de un campo de referencia, una entrada _previous/_user/_trigger o cualquier fórmula — el lenguaje de fórmulas completo está disponible en línea:
{"text": "Paciente ${NAME} (${IF(AGE >= 18, 'adulto', 'menor')}, edad ${AGE}) ahora está ${STATUS}"}
produce:
{"text": "Paciente Amina Yusuf (adulto, edad 34) ahora está Recuperado"}
Utilice comillas simples para el texto dentro de una fórmula en línea, como en IF(AGE >= 18, 'adulto', 'menor') — el lenguaje de fórmulas acepta ambos estilos de comillas, y las comillas simples mantienen legible la plantilla JSON circundante.
Los valores interpolados se escapan automáticamente en formato JSON: las comillas, las barras invertidas y los saltos de línea de sus datos llegan como \", \\ y \n, por lo que una plantilla que es un documento JSON sigue siendo un JSON válido contenga los datos que contenga. Todo lo que está fuera de ${...} se envía exactamente como está escrito —incluidas las secuencias de barra invertida como \n que usted mismo escriba— y una referencia ${...} que no pueda resolverse se deja tal como está escrita.
El editor de plantillas valida cada referencia ${...} con los datos del paso del desencadenador y ofrece la misma lista de campos en la que se puede hacer clic que los pasos de filtro y correo electrónico.