Webhooks
Gestión de endpoints externos que reciben notificaciones push. Eventos suscribibles: certificate_request.created, certificate_request.status_changed, certificate_request.ai_processed, certificate_request.file_uploaded, certificate_request.deleted, certificate.expiring, payment.approved y payment.failed; generan entregas los certificate_request.* y, desde la versión 1.21.1, payment.approved (la orden pasa a PAID) y payment.failed (la orden pasa a FAILED por un pago rechazado). Los de pago salen como máximo una vez por cada cambio de estado de la orden (a PAID o a FAILED); una orden rechazada puede recibir después payment.approved si otro intento de pago de esa misma orden se aprueba, así que antes de crear una orden nueva tras un payment.failed consulte GET /orders/{uuid}. Traen el tipo de orden (order_type: QUOTA_PURCHASE = compra de cupos, CERTIFICATE_RENEWAL = renovación, que no agrega cupos) y el tipo de emisión, la cantidad y la vigencia de la compra; los campos se detallan en la guía Casos de uso, sección Webhooks de pagos. certificate.expiring se acepta en la suscripción, pero todavía no genera entregas. certificate_request.created y certificate_request.status_changed incluyen el tipo de emisión de la solicitud (issuance_flow: BIOMETRIC / DOCUMENTARY). Cada entrega va firmada en la cabecera X-Webhook-Sig con el formato t={timestamp},v1={HMAC-SHA256 del cuerpo}.
Historial de entregas de un webhook
Retorna, paginado y del más reciente al más antiguo, el historial de entregas del webhook indicado (de la empresa del usuario autenticado). Cada evento genera un registro por webhook suscrito. `status`: `pending` mientras se envía; `delivered` si la URL respondió (se guarda `http_status` y hasta 1000 caracteres de la respuesta); `failed` si no hubo respuesta (error de conexión o timeout; el error queda en `response_body`). Nota: una entrega puede permanecer en `pending` de forma indefinida si el envío no llegó a completarse o si fue marcada manualmente para reintento por soporte (en ese caso `attempt` puede ser mayor que 1); no hay reintentos automáticos.
Listar tipos de evento disponibles
Retorna los tipos de evento que se pueden suscribir en un webhook. Generan entregas los eventos certificate_request.* (created, status_changed, ai_processed, file_uploaded, deleted) y, desde la versión 1.21.1, payment.approved (la orden pasa a PAID, también en renovaciones) y payment.failed (la orden pasa a FAILED porque la pasarela rechazó el pago). Los de pago salen una sola vez por cada cambio de estado de la orden (a PAID o a FAILED): los reenvíos de la pasarela no generan otra entrega, y una orden rechazada puede recibir después payment.approved si se paga con otra transacción. Su `data` trae `order_id` (UUID de la orden), `order_type` (QUOTA_PURCHASE = compra de cupos; CERTIFICATE_RENEWAL = renovación, que no agrega cupos), `company_id`, `issuance_flow`, `quantity` y `vigencia` de la compra, `amount`, `currency`, `payment_provider`, `provider_reference`, `provider_transaction_id`, `payment_method_type` y `paid_at` (approved) o `reason` (failed); detalle en la guía Casos de uso, sección Webhooks de pagos. certificate.expiring se acepta en la suscripción, pero todavía no genera entregas. certificate_request.created y certificate_request.status_changed traen el tipo de emisión de la solicitud (`issuance_flow`: BIOMETRIC / DOCUMENTARY). Cada entrega es un POST JSON a la URL del webhook con las cabeceras `X-Webhook-Event` (tipo de evento), `X-Webhook-Source` (nombre de la aplicación) y `X-Webhook-Sig` = `t={timestamp unix},v1={HMAC-SHA256 hexadecimal del cuerpo crudo con el secret del webhook}`. Cuerpo: {'id': 'wh_<ULID>', 'event': '<tipo>', 'created_at': '<ISO 8601>', 'data': {campos propios del evento}}. Timeout de la petición: 10 s. Cada evento se envía una sola vez, sin reintentos. Solo cuentan como fallo los errores de conexión y los timeouts; las respuestas HTTP 4xx/5xx se registran como entregadas (con su código) y reinician el contador. Tras 10 fallos consecutivos el webhook se desactiva automáticamente (is_active = false).
Listar webhooks de la empresa
Retorna, paginados y del más reciente al más antiguo, los webhooks de la empresa del usuario autenticado. No incluye los eliminados ni el `secret`.
Crear webhook
Registra un webhook activo para la empresa del usuario autenticado. Máximo 5 webhooks por empresa (cuentan los activos y los inactivos; los eliminados no). El servidor genera un secret que NO se incluye en esta respuesta: para obtener un secret con el que verificar la firma, llame a POST /webhooks/{id}/rotate-secret después de crearlo.
Obtener detalle de un webhook
Retorna un webhook de la empresa del usuario autenticado (sin `secret`).
Actualizar webhook
Actualización parcial: solo se modifican los campos enviados. `is_active` = true reactiva un webhook desactivado (manual o automáticamente por fallos). Reactivar no reinicia `failure_count`: si el webhook se desactivó por 10 fallos, la siguiente entrega fallida lo vuelve a desactivar; el contador solo vuelve a 0 con una entrega exitosa. El secret no se modifica aquí (ver rotate-secret). Solo se admite PUT.
Eliminar webhook
Elimina el webhook (borrado lógico): deja de recibir entregas, desaparece de los listados y libera un cupo del límite por empresa.
Rotar secret del webhook
Genera un nuevo secret (40 caracteres alfanuméricos) para firmar las entregas y lo retorna. Es la única respuesta que expone el secret: guárdelo en ese momento. El secret anterior deja de usarse de inmediato. No recibe cuerpo. Verificación en el receptor: calcular HMAC-SHA256 (hex) del cuerpo crudo recibido con el secret y compararlo con el valor `v1` de la cabecera `X-Webhook-Sig`.