YoEmito LogoYoEmito
Docs /Webhooks

Webhooks en Tiempo Real

Notificaciones asíncronas HTTP con firma HMAC-SHA256.

POST/v1/webhooks
GET/v1/webhooks/events
GET/v1/webhooks/:id/deliveries

Los webhooks eliminan la necesidad de hacer polling a la API. Recibirás un evento HTTP POST automático cada vez que SUNAT confirme la aprobación o rechazo de un comprobante.

Verificación de Firma HMAC

Cada petición HTTP contiene la cabecera X-YoEmito-Signature: t={timestamp},v1={hmac}, calculada sobre el body crudo exacto que enviamos (antes de cualquier parseo). Verificarla contra el JSON re-serializado por tu framework casi siempre falla, porque el orden de las claves o los espacios pueden cambiar.

Con Node.js, usa verifyWebhookSignature del SDK oficial en vez de reimplementar el HMAC a mano:

import express from "express";
import { verifyWebhookSignature } from "@yoemito/sdk-node";

// express.raw() conserva el body EXACTO (Buffer), no lo parsees antes
app.post(
  "/webhook-receiver",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const rawBody = req.body.toString("utf8");
    const isValid = verifyWebhookSignature(
      process.env.YOEMITO_WEBHOOK_SECRET,
      req.headers["x-yoemito-signature"],
      rawBody,
    );
    if (!isValid) return res.status(401).send("Firma inválida");

    const event = JSON.parse(rawBody);
    // ... procesa event.type / event.data
    res.sendStatus(200);
  },
);

Sin la SDK (otro lenguaje, u otro runtime), replica la misma lógica: HMAC-SHA256(secret, "{t}.{rawBody}") en hexadecimal, comparado con v1 mediante comparación de tiempo constante, rechazando timestamps con más de 300s de antigüedad.

En Fastify o Next.js aplica el mismo principio: captura el body como texto/Buffer crudo antes de que el framework lo parsee a JSON automáticamente.

Catálogo de Eventos

Llama a GET /v1/webhooks/events para obtener la lista completa de eventos disponibles junto con un ejemplo real de payload por cada uno — útil para saber qué suscribir sin tener que provocar cada evento manualmente en Sandbox.

EventoCuándo se dispara
document.acceptedSUNAT aceptó el comprobante (factura/boleta/nota).
document.accepted_with_warningsAceptado con observaciones no bloqueantes.
document.rejectedSUNAT rechazó el comprobante.
document.cdr_readyLa Constancia de Recepción ya está disponible para descarga.
document.queued_sunat_downSUNAT no respondió; se reintentará automáticamente.
document.status_changedGenérico: se emite en toda transición, además del evento específico.
voided.accepted / .rejected / .status_changedEquivalentes para Comunicación de Baja (RA).
summary.accepted / .rejected / .status_changedEquivalentes para Resumen Diario de Boletas (RC).
certificate.expiringEl certificado digital de un emisor vencerá pronto.
api_key.created / .revoked / .deleted / .rotatedActividad sobre las API Keys de la organización.

Historial de Entregas

GET /v1/webhooks/:id/deliveries devuelve el historial de intentos de un webhook (evento, número de intento, código HTTP recibido y error) — también visible desde el panel en Webhooks → Ver entregas. Por privacidad, el payload y la URL de la entrega se purgan una vez resuelta (entregada o agotados los reintentos); el historial retiene solo los metadatos necesarios para diagnosticar un fallo.

Contactar Ventas