Probar los avisos a tu servidor
Envía a tu servidor un aviso de prueba firmado y comprueba que rechaza los falsos, sin esperar a que ocurra un evento real.
Actualizado el . 5 min de lectura
Incluido en todos los planes. Ver precios
UTILIA OS envía a la dirección de avisos de tu aplicación una muestra del evento que elijas, firmada exactamente como una entrega real, y comprueba que tu servidor rechaza los avisos con la firma falsa. Son las únicas pruebas que salen hacia fuera: llegan de verdad a tu servidor.
Antes de empezar
- Integraciones en el plan, y el aplicativo del evento que vas a probar: si no,
403 MODULE_NOT_ENABLED. - La dirección de avisos configurada en la aplicación, que no apunte a una red privada, y los avisos activados.
- Con la clave, las dos pruebas comparten un cupo de 5 al minuto con el panel. Desde la pestaña Pruebas, hace falta el permiso
EXTERNAL_APPS_EDIToINTEGRATIONS_WEBHOOKS_MANAGE. - Una clave de servidor. Con una clave publicada en una web, las dos responden
403 DIAGNOSTICS_NOT_AVAILABLE_FOR_PUBLISHABLE_KEY: lánzalas desde la pestaña Pruebas.
Enviar un aviso de prueba
/api/external/v1/diagnostics/webhook-sampleEnvía a la dirección de avisos de la aplicación una muestra firmada del evento indicado y responde con lo que contestó tu servidor. Exige Integraciones y que el plan incluya el evento. 5 por minuto, compartidos con el panel.
curl -X POST https://os.utilia.ai/api/external/v1/diagnostics/webhook-sample \
-H "X-Api-Key: $UTILIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "INVOICE_CREATED"}'Con WEBHOOK_TEST, la prueba de conexión de siempre. No hace falta que la aplicación esté suscrita al evento, pero la respuesta te dice si lo está (subscribed), porque sin suscripción los avisos reales no te llegarán. Las muestras no quedan en el historial de entregas ni se reintentan.
La respuesta trae success (tu servidor respondió 2xx), statusCode, responseTimeMs, error si no fue bien, event, deliveryId, subscribed, sampleShape, el cuerpo exacto que se envió (payload) y los primeros 500 caracteres de lo que contestó tu servidor (responseSnippet).
La muestra espera la respuesta de tu servidor 10 segundos; una entrega real espera 30. Si tu servidor tarda entre las dos cifras, la muestra falla aunque los avisos reales lleguen: contesta antes y procesa después.
Desde el panel se envía igual, en la pestaña Pruebas, o con la API del panel y tu sesión:
/api/integrations/apps/:id/webhook/testLa misma muestra, lanzada por una persona con sesión. Permiso: EXTERNAL_APPS_EDIT o INTEGRATIONS_WEBHOOKS_MANAGE.
Cómo es un aviso de prueba
Lleva las mismas cabeceras que una entrega real: X-Utilia-Signature, X-Utilia-Webhook-Signatures, X-Utilia-Timestamp, X-Utilia-Event, X-Utilia-Schema-Version y X-Utilia-Delivery-Id, que en las pruebas empieza por test_. El cuerpo lleva dos marcas que los avisos reales no llevan: livemode: false en el sobre y test: true en meta. Los identificadores son inventados y llevan test en el nombre (inv_test_...).
{
"event": "INVOICE_CREATED",
"timestamp": "2026-10-21T10:00:00.000Z",
"app": { "id": "ckapp1234567890", "slug": "mi-integracion" },
"livemode": false,
"data": {
"invoice": {
"id": "inv_test_8f3k2m1q",
"invoiceNumber": "PRUEBA-202600001",
"displayNumber": "PRUEBA-2026-00001",
"status": "ISSUED",
"totalAmount": 30,
"currency": "eur"
},
"externalUser": { "externalId": "user_test_1234" }
},
"meta": { "schemaVersion": "2026-05", "test": true }
}Las muestras de los eventos de facturación (INVOICE_*), de PAYMENT_METHOD_ADDED, PAYMENT_METHOD_REMOVED y de APP_HEALTH_CHANGED tienen la forma de los avisos reales campo por campo; las de los demás eventos son genéricas. sampleShape lo dice: exact o generic. La forma de cada evento está en el Catálogo de eventos.
Primero la firma, después la marca de prueba
Comprueba la firma antes de mirar livemode: las marcas viajan dentro del cuerpo firmado, así que solo te puedes fiar de ellas en un aviso con la firma buena. Después, trata como prueba todo aviso con livemode === false o meta.test === true: respóndelo con 2xx y no lo guardes en tus datos de producción.
Comprobar tu receptor de avisos
Un receptor que acepta cualquier aviso deja que cualquiera se haga pasar por UTILIA OS. Esta comprobación envía tres avisos de prueba y mira qué contesta tu servidor a cada uno.
Comprobación del receptor de avisos
Participan: UTILIA OS, Tu servidor.
De UTILIA OS a Tu servidor:
Aviso bien firmado
Firmado como una entrega real.De Tu servidor a UTILIA OS:
2xx esperado (respuesta)
De UTILIA OS a Tu servidor:
Aviso con la firma falsa
El mismo aviso, firmado con otra clave.De Tu servidor a UTILIA OS:
4xx esperado (respuesta)
De UTILIA OS a Tu servidor:
Aviso caducado
Bien firmado, con la marca de tiempo de hace una hora.De Tu servidor a UTILIA OS:
4xx esperado (respuesta)
/api/external/v1/diagnostics/webhook-receiver-checkEnvía tres avisos WEBHOOK_TEST (firma buena, firma falsa y marca de tiempo caducada) y responde el veredicto y lo que contestó tu servidor a cada uno. Exige Integraciones, dirección, avisos activados y clave de firma.
Cada aviso espera 30 segundos, como una entrega real: prepara tu cliente para esperar hasta un minuto y medio. En los SDK, checkWebhookReceiver() y check_webhook_receiver(), que ya esperan lo necesario. Exige una dirección configurada, los avisos activados y una clave de firma, y comparte el cupo de 5 por minuto con las muestras.
{
"at": "2026-10-21T10:00:00.000Z",
"validAccepted": true,
"invalidSignatureRejected": false,
"staleTimestampRejected": true,
"verdict": "Tu servidor ha aceptado un aviso de prueba con una firma falsa; comprueba que verifica la firma de todos los avisos.",
"attempts": [
{ "kind": "valid", "statusCode": 200, "responseTimeMs": 120, "error": null },
{ "kind": "invalid_signature", "statusCode": 200, "responseTimeMs": 98, "error": null },
{ "kind": "stale_timestamp", "statusCode": 401, "responseTimeMs": 101, "error": null }
]
}El resultado queda guardado, lo lance quien lo lance: el diagnóstico lo usa para el hallazgo webhook-receiver-accepts-invalid-signature y para el paso recorrido-receiver-checked.
Probar tu receptor sin red
Para las pruebas automáticas de tu servidor, los SDK firman un cuerpo en local con la misma cadena que UTILIA OS: sdk.webhooks.signTestPayload(payload, secret) en JavaScript y sign_test_payload(payload, secret) en Python, a partir de la 4.5.0 (si ya se puede instalar lo dice Versiones y compatibilidad). Devuelven el cuerpo en texto, la marca de tiempo, la firma y las cabeceras listas, y sdk.webhooks.verify acepta el resultado. Usa una clave inventada, nunca la de producción. Cómo se calcula la firma sin los SDK está en Firma HMAC de los avisos.
Si algo falla
400 WEBHOOK_NO_URL: la aplicación no tiene dirección de avisos. Configúrala en su ficha.400 WEBHOOK_URL_INVALID: la dirección apunta a una red privada o resuelve a una dirección no permitida.400 VALIDATION_ERROR: el evento no existe. La lista está en el Catálogo de eventos.403 MODULE_NOT_ENABLED: el plan no incluye Integraciones o el aplicativo del evento.403 OUTBOUND_DOMAIN_NOT_ALLOWED: el destino no está en la lista de dominios salientes autorizados de la organización. Lo añade un administrador.409en la comprobación del receptor: los avisos están desactivados o, conWEBHOOK_SECRET_NOT_CONFIGURED, la aplicación no tiene clave de firma.success: falseen la muestra: los avisos están desactivados, con el motivo, o tu servidor no respondió2xxa tiempo.statusCode,erroryresponseSnippetdicen qué contestó.403 TENANT_SUSPENDEDoTENANT_CANCELLED: con la organización suspendida o de baja no se envían avisos de prueba.503 DIAGNOSTICS_UNAVAILABLE: el contador del cupo no responde y la prueba no se lanza sin contarla. Repite en unos minutos.