Ir al contenido

Webhooks

En lugar de sondear, puedes hacer que Accessful envíe por POST un evento firmado a tu servidor en cuanto un trabajo cambie de estado.

No hay panel de control ni endpoint de registro. Adjuntas un callback por cada subida y tú eliges el secreto de firma — Accessful no emite ninguno.

  • Subida multipart — envía los campos de formulario webhookUrl y secret.
  • Subida por URL — envía los campos JSON callbackUrl y hmacSignature.
Ventana de terminal
curl -X POST "https://api.accessful.de/api/v1/upload-service/pdf/upload" \
-H "X-API-Key: $ACCESSFUL_API_KEY" \
-F "files=@documento.pdf" \
-F "webhookUrl=https://tu-app.example.com/hooks/accessful" \
-F "secret=$TU_WEBHOOK_SECRET"
type del eventoSe dispara cuando
case.runningEl trabajo empezó a procesarse. Puede dispararse más de una vez (una por iteración).
case.completedEl resultado PDF/UA está listo para descargar.
case.failedEl procesamiento falló.
case.canceledEl caso fue cancelado.
case.quota_exceededRechazado porque la cuota del contrato está agotada.

Los estados queued y quota_pending no se entregan como webhooks.

El cuerpo de la petición es JSON. Content-Type: application/json.

{
"id": "f1d2c3b4-0000-4a1e-8f3c-2d6b5a9e1c40",
"type": "case.completed",
"apiVersion": "2026-06-05",
"occurredAt": "2026-06-05T12:34:56Z",
"data": {
"caseId": "7c2f1e4a-9b0d-4a1e-8f3c-2d6b5a9e1c40",
"fileName": "documento.pdf",
"jobStatus": "completed"
}
}
CampoTipoNotas
idUUIDID del evento. Úsalo como clave de idempotencia (ver abajo).
typestringUno de los tipos de evento anteriores.
apiVersionstringVersión del contrato (2026-06-05). Fíjala para detectar cambios.
occurredAtISO-8601Cuándo se creó el evento; estable entre reintentos.
data.caseIdUUIDEl caso al que se refiere este evento.
data.fileNamestringEl nombre del archivo.
data.jobStatusstringEstado bruto del trabajo, p. ej. completed, failed, canceled, quota_exceeded.

Los campos nulos se omiten del JSON.

CabeceraEjemploPropósito
X-Accessful-Signaturet=1749126896,v1=9f86d0…Firma HMAC — verifica esta
X-Accessful-Webhook-Timestamp1749126896Segundos Unix; igual que t= arriba
X-Accessful-Event-Idf1d2c3b4-…Igual que id; clave de idempotencia
X-Accessful-Event-Typecase.completedEnrutado sin analizar el cuerpo
X-Accessful-Case-Id7c2f1e4a-…El ID del caso
X-Accessful-Delivery-Attempt1Contador de intentos, empieza en 1
X-Signaturen4bQgY…legacy HMAC en base64 solo sobre el cuerpo

La cabecera X-Accessful-Signature tiene la forma t=<unix>,v1=<hex>. Recalcúlala y compárala en tiempo constante:

  1. Lee t y v1 de la cabecera.
  2. Calcula HMAC-SHA256(secret, "<t>.<cuerpo bruto>") y codifícalo en hexadecimal. La cadena firmada es el timestamp, un punto literal y luego el cuerpo bruto exacto de la petición — verifícalo antes de analizar el JSON.
  3. Compara en tiempo constante contra v1.
  4. Opcionalmente, rechaza si t tiene más de unos minutos (protección frente a repetición).
import crypto from 'node:crypto';
// `rawBody` deben ser los bytes exactos recibidos (p. ej. express.raw()).
function verify(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 min
return valid && fresh;
}
  • Éxito = cualquier respuesta 2xx dentro del tiempo límite (5s para conectar, 10s para responder). Responde rápido y haz tu trabajo de forma asíncrona.
  • Fallo (no-2xx, timeout o error de conexión) se reintenta hasta 10 veces con retroceso exponencial y jitter — aproximadamente 10s → 30s → 1,5m → 4,5m → 13,5m → 40m → 2h, luego limitado a 6h, menos hasta un 20% de jitter. La ventana completa abarca varias horas.
  • Tras 10 intentos fallidos, el evento se abandona. Contacta con soporte para reenviarlo.
  • Idempotencia: el mismo evento puede llegar más de una vez (p. ej. un reintento después de que tu endpoint ya respondiera con éxito). Deduplica por X-Accessful-Event-Id — es estable en cada reintento.