Ir al contenido

Webhooks de documentos

Ver como Markdown Lee esta página como texto plano Abrir en ChatGPT Haz preguntas sobre esta página Abrir en Claude Haz preguntas sobre esta página Abrir en Perplexity Haz preguntas sobre esta página

Cuando creas un documento con el campo webhook, Verificamex Firma te avisa cada vez que ese documento se crea o cambia: cuando subes el PDF, cuando alguien firma, cuando alguien rechaza y cuando el documento queda firmado por completo.

Cada aviso es una petición POST a tu URL con el estado completo del documento en ese momento, en formato JSON.


AspectoComportamiento
MétodoPOST
EncabezadosContent-Type: application/json, más X-Verificamex-Firma-Signature (la firma del aviso) y X-Verificamex-Firma-Event-Id (su identificador, igual en los reintentos). Ver Seguridad de webhooks.
CuerpoEl documento completo (ver Campos del documento). No hay un campo de “tipo de evento”: el evento se deduce de los valores (ver Cómo identificar qué pasó).
Tiempo de envíoLos avisos se envían en ciclos de un minuto, así que pueden tardar hasta ~1 minuto en llegar después del cambio.
ÉxitoCualquier respuesta 2xx. Responde en menos de 10 segundos; si necesitas procesar algo pesado, responde primero y procesa después.
ReintentosSi tu servidor responde con otro código o no responde, el aviso se reintenta en el siguiente ciclo, hasta 3 intentos en total. Después se descarta.

Se envía un aviso cada vez que el documento se guarda con cambios. Estos son los momentos principales:

MomentosignedQué cambia en el cuerpo
Se crea el documento1Pueden llegar varios avisos casi al mismo tiempo, con todos los firmantes en PENDING. Si lo creaste por API, file viene vacío ("") y spectators viene vacío aunque hayas enviado espectadores.
Se sube el PDF1file trae el nombre del archivo y spectators ya incluye a los espectadores.
Firma un firmante y aún faltan otros2Ese firmante pasa a SIGNED con signedAt y signature. signed_at del documento se actualiza.
Firma el último firmante3Todos los firmantes en SIGNED. xml_with_signs deja de ser null.
Un firmante rechaza4Ese firmante pasa a REJECTED. reject_commentary trae su comentario. El resto se queda en PENDING.

Otros cambios en el documento, como actualizar sus firmantes, también envían un aviso con el estado actual.


CampoTipoValores posibles / Descripción
idstringIdentificador del documento (UUID).
filestringNombre del archivo PDF. Vacío ("") si el documento se creó por API y aún no se sube el PDF.
triesintNúmero máximo de recordatorios configurado al crear el documento.
remember_everyintCada cuántos días se envían los recordatorios.
remember_atstringHora de los recordatorios (HH:mm).
signedintEstado del documento. Ver Estados del documento.
signed_atstring | nullFecha y hora del último movimiento de firma (una firma o un rechazo). Con signed: 3 es el momento en que se completó. null mientras nadie haya firmado ni rechazado.
xml_with_signsstring | nullReferencia interna al XML con las firmas. Solo tiene valor con signed: 3. No es una URL: para obtener el archivo usa Descargar XML.
webhookstringLa URL de webhook configurada (la tuya).
redirect_urlstringURL de redirección del documento. Solo aparece si la configuraste; si no, el campo no viene.
reject_commentarystring | nullComentario que dejó quien rechazó. Puede venir con formato HTML (por ejemplo, <p>No estoy de acuerdo</p>). null si nadie ha rechazado.
signaturesArrayFirmantes del documento. Ver Campos de cada firmante.
spectatorsArrayEspectadores del documento. Puede venir vacío; en los avisos de creación siempre viene vacío y los espectadores aparecen desde el aviso de subida del PDF. Ver Campos de cada espectador.
sign_positionstringUPPER_RIGHT, UPPER_LEFT, LOWER_RIGHT, LOWER_LEFT, NONE o CUSTOM.
modestringModo de firmado: CLASSIC, PDF_SIGNATURE o CLASSIC_BATCH.
notification_modestringENABLED o DISABLED.
logo_modestringFULL_BRANDING, MEDIUM_BRANDING, NO_BRANDING o NO_SIGNATURE_SHEET.
orderedstringACTIVE (firma en orden) o INACTIVE.
company_idstringCarpeta de trabajo del documento.
created_atstringFecha de creación del documento.
updated_atstringFecha del último cambio. Úsala para ordenar los avisos.

Las fechas vienen en formato ISO 8601 sin zona horaria (por ejemplo, 2026-05-04T20:14:56.945158). La cantidad de decimales de los segundos puede variar.

ValorSignificado
1Sin firmas. Nadie ha firmado ni rechazado todavía.
2Firmado parcialmente. Al menos un firmante firmó y faltan otros.
3Firmado. Todos los firmantes firmaron.
4Rechazado. Un firmante rechazó el documento y el proceso termina.
CampoTipoValores posibles / Descripción
idstringIdentificador del firmante. Es el signatureId que se usa en Firma vía API.
signatureIdstringMismo valor que id.
namestringNombre del firmante.
emailstringCorreo del firmante.
phonestring | nullTeléfono del firmante, si se envió.
rfcstring | nullRFC del firmante, si se conoce.
curpstring | nullCURP del firmante, si se conoce.
nameSource, emailSource, rfcSource, curpSourcestring | nullCopias de name, email, rfc y curp. Usa los campos principales.
orderintPosición del firmante, empezando en 0. Importa cuando ordered es ACTIVE.
signedstringEstado del firmante: PENDING, SIGNED o REJECTED.
signedAtstring | nullFecha en que firmó. null si no ha firmado (también si rechazó).
signaturestring | nullFirma digital en Base64. null si no ha firmado.
tryintNúmero de recordatorio en el que va el firmante. Empieza en 1.
rememberAtstringFecha del siguiente recordatorio (YYYY-MM-DD).
positionsArray | nullPosiciones de firma si el documento usa sign_position: "CUSTOM"; cada una con posX, posY, width, height, page y rotation. null en otro caso.
allowedSignatureMethodsArray | nullMétodos de firma permitidos para este firmante (FIREL, EFIRMA, IDENTITY, SIMPLE). null si no se limitaron.
createdAtstringFecha de alta del firmante.
updatedAtstringFecha del último cambio del firmante.
CampoTipoDescripción
idintIdentificador numérico del espectador.
namestringNombre del espectador.
emailstringCorreo del espectador.
createdAtstringFecha de alta del espectador.
updatedAtstringFecha del último cambio del espectador.

Los ejemplos usan un documento con dos firmantes (Juan Perez y Maria Lopez) y un espectador. Los datos son ficticios.

Documento con el PDF ya subido y ningún firmante ha actuado.

{
"id": "ac110005-9df4-1d1b-819d-f5eac471003a",
"file": "contrato-servicios.pdf",
"tries": 3,
"remember_every": 3,
"remember_at": "12:30",
"signed": 1,
"signed_at": null,
"xml_with_signs": null,
"webhook": "https://tudominio.com/webhooks/verificamex-firma",
"redirect_url": "https://tudominio.com/fin-firma",
"reject_commentary": null,
"signatures": [
{
"id": "ac110005-9df4-1d1b-819d-f5eac478003b",
"email": "jpe@gmail.com",
"phone": "+522291449388",
"name": "Juan Perez",
"rememberAt": "2026-05-07",
"rfc": null,
"curp": null,
"signature": null,
"signed": "PENDING",
"try": 1,
"createdAt": "2026-05-04T20:14:56.888302",
"updatedAt": "2026-05-04T20:14:56.888310",
"positions": null,
"allowedSignatureMethods": null,
"order": 0,
"signatureId": "ac110005-9df4-1d1b-819d-f5eac478003b",
"emailSource": "jpe@gmail.com",
"signedAt": null,
"nameSource": "Juan Perez",
"rfcSource": null,
"curpSource": null
},
{
"id": "ac110005-9df4-1d1b-819d-f5eac47a003c",
"email": "mlopez@tudominio.com",
"phone": null,
"name": "Maria Lopez",
"rememberAt": "2026-05-07",
"rfc": null,
"curp": null,
"signature": null,
"signed": "PENDING",
"try": 1,
"createdAt": "2026-05-04T20:14:56.891004",
"updatedAt": "2026-05-04T20:14:56.891010",
"positions": null,
"allowedSignatureMethods": null,
"order": 1,
"signatureId": "ac110005-9df4-1d1b-819d-f5eac47a003c",
"emailSource": "mlopez@tudominio.com",
"signedAt": null,
"nameSource": "Maria Lopez",
"rfcSource": null,
"curpSource": null
}
],
"spectators": [
{
"id": 88416,
"name": "Hector Lavoe",
"email": "hl@hotmail.com",
"createdAt": "2026-05-04T20:14:56.918561",
"updatedAt": "2026-05-04T20:14:56.918583"
}
],
"sign_position": "LOWER_RIGHT",
"mode": "PDF_SIGNATURE",
"notification_mode": "ENABLED",
"logo_mode": "FULL_BRANDING",
"ordered": "INACTIVE",
"company_id": "ac110005-9d0c-1243-819d-0c3b71220000",
"created_at": "2026-05-04T20:14:56.945158",
"updated_at": "2026-05-04T20:16:10.402771"
}

Como el cuerpo siempre es el documento completo, compara lo que recibes con lo último que guardaste:

  1. Valida la firma: si no coincide, responde 401 y descarta el aviso (ver Seguridad de webhooks).
  2. Descarta avisos viejos: si updated_at es menor o igual al último que procesaste para ese id, ignóralo.
  3. Revisa signed: 3 significa que ya puedes descargar el PDF firmado; 4 significa que el proceso terminó por rechazo y el motivo está en reject_commentary.
  4. Revisa cada firmante: el que cambió de PENDING a SIGNED o REJECTED es quien acaba de actuar.
// Ejemplo con Express. verifyVerificamexFirmaSignature está en "Seguridad de webhooks".
app.post('/webhooks/verificamex-firma', express.raw({ type: 'application/json' }), async (req, res) => {
if (!verifyVerificamexFirmaSignature(req.body, req.get('X-Verificamex-Firma-Signature'), WEBHOOK_SECRET)) {
return res.sendStatus(401); // No lo envió Verificamex Firma o lo modificaron.
}
res.sendStatus(200); // Responde rápido; procesa después.
const doc = JSON.parse(req.body.toString('utf8'));
const previous = await db.documents.find(doc.id);
if (previous && previous.updated_at >= doc.updated_at) return; // Aviso viejo o repetido.
switch (doc.signed) {
case 1: /* Sin firmas */ break;
case 2: /* Firmado parcialmente */ break;
case 3: /* Firmado: descarga el PDF firmado */ break;
case 4: /* Rechazado: doc.reject_commentary */ break;
}
await db.documents.save(doc);
});