Recibe notificaciones HTTP automáticas cuando todos los firmantes completan el proceso de firma biométrica.
POSTJSON1 (sin reintentos)URL para descargar el ZIP de trazabilidad WORM con selfies, fotos, analisis biometrico, sesiones y logs de cada firmante. Mismo token Bearer. null si no hay logs disponibles.
webhook_token solo se muestra una vez — al crear el documento. Guárdalo en una variable de entorno o almacén de secretos.curl -X POST 'https://api.manyao.pe/v1/documents' \
-H 'Authorization: Bearer {{token}}' \
-H 'Content-Type: application/json' \
-d '{
"title": "Contrato",
"content_type": "PDF",
"content_base64": "JVBERi0x...",
"content_hash": "sha256:...",
"signers": [{"dni": "12345678", "doc_type": "dni-pe"}],
"callback_url": "https://tu-app.com/webhooks/manyao"
}' {
"document_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"webhook_token": "4a7f2b9c1e3d8a0f...",
"callback_url": "https://tu-app.com/webhooks/manyao"
}Cada notificación incluye el header Authorization: Bearer {webhook_token}. Valida este token antes de procesar el payload.
POST /webhooks/manyao HTTP/1.1
Content-Type: application/json
Authorization: Bearer 4a7f2b9c1e3d8a0f...
X-Manyao-Event: document.completedv1/documents/ se recibe el webhook_token que no es el mismo que el access_token. Usted debe guardarlo en su plataforma de registro de secretos asociado al webhook_token.| Evento | Descripción | Estado |
|---|---|---|
| document.completed | Todos los firmantes completaron — PDF final generado | ✅ Implementado |
| signer.completed | Un firmante individual completó su firma | 🔜 Próximamente |
| document.expired | El documento expiró sin completarse | 🔜 Próximamente |
| signer.rejected | Un firmante fue rechazado por validación biométrica | 🔜 Próximamente |
Evento document.completed — enviado cuando el PDF final ha sido generado:
{
"event": "document.completed",
"document_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Contrato de Servicios",
"status": "completed",
"pdf_hash": "sha256:e3b0c44298fc1c149afb...",
"signers_completed": 2,
"signers_total": 2,
"signers": [
{
"id": 1, "dni": "12345678", "doc_type": "dni-pe",
"status": "completed", "score": 98.5,
"signed_at": "2026-03-22T10:30:00",
"verified_name": "JUAN PEREZ GARCIA"
},
{
"id": 2, "dni": "87654321", "doc_type": "dni-pe",
"status": "completed", "score": 96.2,
"signed_at": "2026-03-22T10:45:00",
"verified_name": "MARIA LOPEZ TORRES"
}
],
"completed_at": "2026-03-22T10:45:01",
"download_url": "https://api.manyao.pe/v1/documents/a1b2c3d4.../download",
"download_log_url": "https://api.manyao.pe/v1/documents/a1b2c3d4.../log-download"
}| Campo | Tipo | Descripción |
|---|---|---|
event | string | Siempre document.completed |
document_uuid | string | UUID único del documento |
title | string | Título del documento tal como fue creado |
status | string | Siempre completed en este evento |
pdf_hash | string | Hash SHA-256 del PDF firmado (sha256:...). Úsalo para verificar integridad |
signers_completed | integer | Número de firmantes que completaron |
signers_total | integer | Total de firmantes requeridos |
signers | array | Lista de objetos firmante (ver tabla abajo) |
completed_at | datetime | Fecha y hora de finalización (ISO 8601) |
download_url | string | URL del PDF firmado. Requiere Bearer token del documento |
download_log_url | string | null | URL del ZIP de trazabilidad WORM. Requiere Bearer token. null si no disponible |
signer (dentro del array)| Campo | Tipo | Descripción |
|---|---|---|
id | integer | ID interno del firmante |
dni | string | Número de documento enviado al crear el firmante |
doc_type | string | dni-pe, dni-pa o ci-pe |
status | string | Siempre completed en este evento |
score | float | null | Puntuación biométrica 0–100. Valores ≥ 75 son aceptados |
signed_at | datetime | null | Fecha y hora en que el firmante completó (ISO 8601) |
verified_name | string | null | Nombre completo verificado por biometría |
El payload incluye download_url (PDF firmado) y download_log_url (ZIP de trazabilidad WORM). Ambas URLs se autentican con el mismo Bearer token con el que se creó el documento.
curl -L '{{download_url}}' \
-H 'Authorization: Bearer {{access_token}}' \
-o documento-firmado.pdfEl ZIP contiene todos los archivos de auditoría del proceso: hashes, registros de validación biométrica, tiempos y evidencias de cada paso. Es inmutable y puede usarse como prueba legal.
curl -L '{{download_log_url}}' \
-H 'Authorization: Bearer {{access_token}}' \
-o trazabilidad.zipaccess_token es el Bearer token recibido al crear el documento (campo access_token en la respuesta del POST /v1/documents). Guárdalo junto con el webhook_token.HTTP/1.1 200 OK
Content-Type: application/json
{"received": true}Al recibir una respuesta HTTP 2xx, Manyao elimina permanentemente todos los datos sensibles: PDF original, imágenes de firma, datos biométricos, fotos del documento y selfies de verificación.
app.post('/webhooks/manyao', async (req, res) => {
// 1. Validar el Bearer token
const auth = req.headers['authorization'] || '';
const token = auth.replace('Bearer ', '');
if (token !== process.env.MANYAO_WEBHOOK_TOKEN) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { event, document_uuid, title, signers, pdf_hash } = req.body;
if (event === 'document.completed') {
// IMPORTANTE: descarga el PDF ANTES de responder 200
await downloadSignedPdf(document_uuid);
console.log('Documento completado:', title);
console.log('Firmantes:', signers.map(s => s.verified_name).join(', '));
console.log('Hash del PDF:', pdf_hash);
}
// Responder 200 — confirma recepción y activa la purga en Manyao
res.status(200).json({ received: true });
});// webhooks/manyao.php
// 1. Validar el Bearer token
$auth = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$token = str_replace('Bearer ', '', $auth);
if ($token !== getenv('MANYAO_WEBHOOK_TOKEN')) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$payload = json_decode(file_get_contents('php://input'), true);
if ($payload['event'] === 'document.completed') {
// IMPORTANTE: descarga el PDF ANTES de responder 200
downloadSignedPdf($payload['document_uuid']);
foreach ($payload['signers'] as $signer) {
// $signer['verified_name'], $signer['score'], $signer['signed_at']
}
}
// Responder 200 — confirma recepción y activa la purga en Manyao
http_response_code(200);
echo json_encode(['received' => true]);