Ir al contenido

Recibir webhooks

Un webhook es AssinaJá llamando a la puerta de su sistema cuando le ocurre algo a un documento, en lugar de que su sistema tenga que preguntar continuamente. Es una petición POST que la plataforma hace a una dirección suya.

Esta página es para quien integra AssinaJá con otro programa. Si solo quiere ver qué ha pasado con un documento, use el historial del documento.

Los webhooks de la organización se configuran en Configuración → Desarrolladores → Webhooks, y solo el Propietario de la organización tiene acceso a esa pestaña. La página tiene tres partes: URL y eventos, Secreto del webhook y, debajo, Entregas.

En URL y eventos:

  1. En URL del webhook, escriba la dirección de su sistema: «HTTPS, puerto 443 u 8443, en una dirección pública. Se rechazan los nombres internos y las direcciones privadas.»
  2. En Eventos que recibir, elija los eventos; consulte Los eventos. «Si no elige eventos, no se envía nada. Elija al menos uno.»
  3. Compruebe que Envío activo está activado y pulse Guardar.

Enviar evento de prueba hace una petición a la dirección e indica qué ha respondido: «La URL ha respondido {código}.» o «El envío de prueba ha fallado: {error}».

La dirección no es libre. La plataforma la valida antes de guardarla, para que no se pueda usar para llamar a máquinas que no son suyas:

  • HTTPS, siempre.
  • Puerto 443 u 8443, y ningún otro.
  • Un host público: ni localhost, ni *.localhost, ni *.internal, ni metadata.google.internal.
  • Una dirección pública. Si el nombre se resuelve en una dirección privada o reservada (10.x, 172.16–31.x, 192.168.x, 127.x, 169.254.x, 100.64.x, multicast o sus equivalentes en IPv6), se rechaza. Se comprueban todas las direcciones en las que se resuelve el nombre, no solo la primera.

El rechazo aparece en su idioma:

Rechazo Qué hacer
«Indique la URL del webhook.» el campo está vacío
«La dirección no es una URL válida.» falta el esquema o hay un error de escritura
«La URL debe usar HTTPS.» cambie http:// por https://
«El puerto debe ser 443 u 8443.» quite el puerto de la dirección o use uno de estos
«El host está reservado (localhost, .internal, metadatos de la nube) y no puede recibir webhooks.» use un nombre accesible desde internet
«La dirección IP no es pública.» ha escrito una IP privada directamente
«El nombre de host no se resuelve en ninguna dirección.» compruebe el DNS
«No se ha podido resolver el nombre de host.» el DNS ha fallado; inténtelo de nuevo
«El host se resuelve en una dirección que no es pública.» el nombre apunta al interior de su red

Al elegir los eventos, «Uno de los eventos elegidos no se reconoce.» significa que la lista enviada contiene un nombre que la plataforma no conoce; compruébelo en la tabla de los eventos, más abajo. Y «No hay ninguna URL de webhook configurada: indique una o guarde primero la suscripción.» aparece cuando se intenta suscribir eventos antes de que haya dirección.

Evento En pantalla Cuándo se envía
document.completed Documento completado Todos han firmado y el documento final está listo
document.rejected Documento rechazado Un firmante lo ha rechazado
document.canceled Documento cancelado El documento se ha cancelado
document.expired Documento caducado Ha vencido el plazo sin completarse
document.pdf_application_failed Error al aplicar las firmas en el PDF No se ha podido aplicar la firma al PDF
recipient.signed El firmante ha firmado Un firmante ha firmado; una vez por firmante
document.sent Documento enviado para firma El documento se ha publicado y han salido las invitaciones

Los dos últimos no son finales: el documento sigue avanzando después de ellos. No trate ningún evento como «ha terminado»: consulte el estado del documento que viene en el cuerpo.

document.pdf_application_failed es el que no se debe ignorar: significa que alguien ha firmado pero la firma no ha llegado a entrar en el archivo. En AssinaJá aparece como Problema técnico en el detalle del documento, con Reintentar; consulte Seguir y gestionar documentos.

La cabecera Idempotency-Key sirve para que su sistema descarte repeticiones, pero no tiene una sola forma. Depende del destino del evento y de cuál sea:

Destino Evento Clave
Dirección del documento (webhookUrl) cualquiera, salvo recipient.signed {documentPublicId}:{event}
Dirección del documento recipient.signed {documentPublicId}:{event}:{recipientId}
Dirección de la organización cualquiera, salvo recipient.signed {documentPublicId}:{event}:org
Dirección de la organización recipient.signed {documentPublicId}:{event}:{recipientId}:org

Guarde y compare la clave entera, como un texto opaco. No la divida en partes. Si tiene una restricción de unicidad sobre (documento, evento) en su base de datos, rechazará entregas legítimas: recipient.signed llega una vez por firmante, y un documento con dirección propia en una organización que también tiene dirección configurada genera dos entregas del mismo evento, con claves distintas.

El secreto es lo que le permite tener la certeza de que la petición procede realmente de AssinaJá. Está en Configuración → Desarrolladores, en la pestaña Webhooks, en la tarjeta Secreto del webhook. Solo lo ve el Propietario de la organización.

Secreto del webhook:

El secreto se utiliza para verificar la firma de los eventos enviados a su webhook.

Use Generar secreto la primera vez, y Copiar para guardarlo. A partir de ahí, la tarjeta muestra el secreto oculto, con Copiar y Rotar. No salga de esa página sin haberlo guardado:

Guarde este valor ahora: no se volverá a mostrar.

Rotar genera un secreto nuevo sin interrumpir las entregas:

¿Está seguro de que desea rotar el secreto? El secreto anterior seguirá siendo válido durante 24 horas.

Durante esas 24 horas («Secreto anterior válido 24 h más.»), las peticiones van firmadas con los dos secretos, separados por comas en la misma cabecera. Por eso la verificación tiene que aceptar una lista, y no un único valor. Pasado ese plazo, solo se usa el nuevo.

Cada petición trae estas cabeceras:

Cabecera Qué es
X-AssinaJa-Signature La firma, v1=<hex>, o varias separadas por comas durante una rotación
X-AssinaJa-Event El nombre del evento
X-AssinaJa-Delivery Un identificador nuevo en cada intento: no sirve para descartar repeticiones
X-AssinaJa-Timestamp La hora, en segundos Unix
Idempotency-Key Consulte la tabla anterior: cuatro formas posibles

La firma es un HMAC-SHA256 sobre la hora y el cuerpo de la petición unidos por un punto ({timestamp}.{cuerpo}), en hexadecimal en minúsculas y con el prefijo v1=.

La clave no es el secreto tal como lo copió. El secreto viene codificado en base64url; la clave del HMAC son los bytes que resultan de descodificarlo. Pasar el texto directamente a la función de HMAC produce una firma que nunca coincide: es la causa más habitual de que la verificación falle.

const crypto = require('crypto');
function verifyWebhookSignature(secret, timestamp, body, signatureHeader) {
const message = `${timestamp}.${body}`;
// o segredo é base64url — a chave são os bytes descodificados, não o texto
const secretBytes = Buffer.from(secret, 'base64url');
const expected = 'v1=' + crypto
.createHmac('sha256', secretBytes)
.update(message)
.digest('hex');
// durante uma rotação vêm as duas assinaturas
const signatures = signatureHeader.split(',').map(s => s.trim());
return signatures.some(sig => sig === expected);
}

Use el cuerpo tal como llegó, en bruto. Si lo pasa por un analizador de JSON y lo vuelve a serializar, los bytes cambian y la firma deja de coincidir.

Lo que responde Qué ocurre
2xx Entregada. No hay nuevo intento. El cuerpo de la respuesta tiene que caber en 4 KB.
3xx Vuelve a intentarlo: las redirecciones no se siguen.
4xx Vuelve a intentarlo, igual que con un 5xx.
5xx Vuelve a intentarlo.
Sin respuesta en 10 segundos Vuelve a intentarlo.

Solo una respuesta 2xx cuenta como entregada. No existe ningún código que haga que la plataforma desista a propósito: si quiere que una entrega se detenga, responda 2xx y descarte el contenido en su sistema.

Los intentos se espacian 1 min, 2 min, 5 min, 15 min, 30 min, 60 min y 60 min. Son ocho en total, y el octavo es una entrega real: solo cuando falla, la entrega queda marcada como fallida.

El detalle de cada documento muestra la última entrega de ese documento, sea cual sea el evento, en la tarjeta Integración, con Webhook (el nombre del evento), Estado, Intentos, Entregado el y, si ha fallado, el Error. Es el lugar más rápido para distinguir «AssinaJá no lo ha enviado» de «mi servidor no lo ha aceptado». Esta tarjeta no tiene botón de reenvío.

Para ver el historial completo de la organización y reenviar entregas fallidas, vaya a Configuración → Desarrolladores → Webhooks, a la sección Entregas, debajo de la dirección y del secreto:

Cada evento enviado, con la respuesta de su URL. Las entregas fallidas se pueden reenviar.

Cada fila tiene Evento, URL, Estado (Entregada o Fallida), Intentos, Fecha y Último error; las fallidas tienen Reenviar, que responde «Entrega reenviada. La URL ha respondido {código}.» Solo el Propietario de la organización tiene acceso a esa pantalla.

Cuando el reenvío no funciona, la pantalla indica por qué:

Esa entrega ya no existe.

Esa entrega ya se ha recibido: solo se reenvían las fallidas.

No se puede reenviar esta entrega en este momento.