Webhooks
Descripción general
Los webhooks te permiten recibir notificaciones en tiempo real cuando las extracciones se completan o fallan. En lugar de consultar la API periódicamente, DocMap envía una solicitud POST a tu endpoint con el resultado de la extracción tan pronto como el estado cambia.
Datos clave:
- Máximo 10 webhooks activos por cuenta
- Los payloads se firman con HMAC-SHA256 para que puedas verificar su autenticidad
- El timeout de entrega es de 10 segundos por webhook
- La entrega es de tipo "enviar y olvidar" -- el fallo de un webhook no bloquea a los demás
Crear un webhook
Desde el panel de control
- Navega a Webhooks en tu panel de control de DocMap
- Haz clic en Crear webhook
- Introduce la URL de tu endpoint (debe ser HTTPS en producción)
- Selecciona a qué eventos suscribirte
- Copia el secreto de firma inmediatamente -- no se volverá a mostrar
Desde la API
curl -X POST https://api.docmap.io/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/docmap",
"events": ["extraction.completed", "extraction.failed"]
}'const response = await fetch("https://api.docmap.io/v1/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://your-app.com/webhooks/docmap",
events: ["extraction.completed", "extraction.failed"],
}),
});
const { data } = await response.json();
// Store this immediately -- it will never be shown again
console.log("Signing Secret:", data.secret);
console.log("Webhook ID:", data.webhook.id);import requests
response = requests.post(
"https://api.docmap.io/v1/webhooks",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json={
"url": "https://your-app.com/webhooks/docmap",
"events": ["extraction.completed", "extraction.failed"],
},
)
data = response.json()["data"]
# Store this immediately -- it will never be shown again
print("Signing Secret:", data["secret"])
print("Webhook ID:", data["webhook"]["id"])WARNING
El secreto de firma solo se devuelve una vez cuando se crea el webhook. Almacénalo de forma segura en una variable de entorno o gestor de secretos.
Formato del payload
Cuando ocurre un evento, DocMap envía una solicitud POST a la URL de tu webhook con la siguiente estructura:
{
"event": "extraction.completed",
"data": {
"id": "extract-abc123",
"userId": "uid_xyz789",
"templateId": "tpl_inv001",
"templateName": "Standard Invoice",
"fileName": "invoice-march.pdf",
"status": "completed",
"extractedData": {
"vendor_name": "Acme Corp",
"invoice_number": "INV-2024-003",
"total_amount": 4750.00
},
"error": null,
"variables": [...],
"source": "api",
"runId": null,
"processingTimeMs": 3842,
"createdAt": "2024-11-20T14:30:00.000Z"
},
"timestamp": "2024-11-20T14:30:04.000Z"
}Encabezados
Cada solicitud de webhook incluye estos encabezados:
| Encabezado | Descripción |
|---|---|
Content-Type | application/json |
X-DocMap-Signature | Firma HMAC-SHA256: sha256={hex_digest} |
X-DocMap-Event | Nombre del evento (por ejemplo, extraction.completed) |
Verificar firmas
Siempre verifica el encabezado X-DocMap-Signature para confirmar que la solicitud proviene de DocMap. La firma es un hash HMAC-SHA256 del cuerpo de la solicitud sin procesar, usando tu secreto de firma como clave.
import { createHmac, timingSafeEqual } from 'node:crypto'
function verifyWebhookSignature(
body: string,
signature: string,
secret: string,
): boolean {
const expected = createHmac('sha256', secret)
.update(body)
.digest('hex')
const received = signature.replace('sha256=', '')
return timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex'),
)
}
// Express example
app.post('/webhooks/docmap', (req, res) => {
const signature = req.headers['x-docmap-signature'] as string
const body = JSON.stringify(req.body)
if (!verifyWebhookSignature(body, signature, process.env.DOCMAP_WEBHOOK_SECRET!)) {
return res.status(401).send('Invalid signature')
}
const { event, data } = req.body
console.log(`Received ${event} for extraction ${data.id}`)
// Process the webhook...
res.status(200).send('OK')
})import hmac
import hashlib
def verify_webhook_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode('utf-8'),
body,
hashlib.sha256,
).hexdigest()
received = signature.replace('sha256=', '')
return hmac.compare_digest(expected, received)
# Flask example
from flask import Flask, request
app = Flask(__name__)
@app.post('/webhooks/docmap')
def handle_webhook():
signature = request.headers.get('X-DocMap-Signature', '')
body = request.get_data()
if not verify_webhook_signature(body, signature, WEBHOOK_SECRET):
return 'Invalid signature', 401
payload = request.get_json()
event = payload['event']
data = payload['data']
print(f"Received {event} for extraction {data['id']}")
# Process the webhook...
return 'OK', 200TIP
Siempre usa una comparación de tiempo constante (como timingSafeEqual o hmac.compare_digest) para prevenir ataques de temporización.
Referencia de eventos
| Evento | Activación |
|---|---|
extraction.completed | Una extracción finalizó exitosamente. data.status es "completed" y data.extractedData contiene los resultados. |
extraction.failed | Una extracción falló. data.status es "failed" y data.error contiene el mensaje de error. |
Mejores prácticas
Usa HTTPS. Siempre usa un endpoint HTTPS para la URL de tu webhook. Los endpoints HTTP pueden ser rechazados en producción.
Verifica las firmas. Siempre verifica el encabezado
X-DocMap-Signatureantes de procesar un webhook. Esto confirma que la solicitud proviene de DocMap y no ha sido manipulada.Responde rápidamente. Devuelve un código de estado 2xx en pocos segundos. DocMap espera hasta 10 segundos por una respuesta. Si tu procesamiento tarda más, confirma la recepción del webhook inmediatamente y procésalo de forma asíncrona.
Maneja duplicados. En casos raros, un webhook puede entregarse más de una vez. Usa el
idde la extracción para deduplicar si es necesario.Almacena el secreto de forma segura. Mantén tu secreto de firma en una variable de entorno o gestor de secretos. Nunca lo codifiques directamente en el código fuente ni lo subas al control de versiones.
Monitorea los fallos. Si tu endpoint está fallando consistentemente, considera revisar los logs de tu servidor. DocMap registra los fallos de entrega pero no reintenta.
