Docs/Webhooks

Webhooks

Cuando se utiliza delivery_mode: webhook, Apertur realiza un POST de las imágenes a su endpoint a medida que se procesan.

Encabezados de solicitud

EncabezadoDescripción
X-Aptr-SignatureFirma HMAC-SHA256 del cuerpo de la solicitud
X-Aptr-Session-IdEl ID de la sesión de subida
X-Aptr-Image-IndexÍndice basado en 0 de esta imagen dentro de la sesión
X-Aptr-Image-IdID único de la imagen
Content-TypeDepende del formato: multipart/form-data, application/json o application/octet-stream

Formatos de webhook

multipart(predeterminado)

La imagen se envía como un POST multipart/form-data. El nombre del campo del archivo es image. Las etiquetas de la sesión se incluyen como campos de formulario adicionales.

Content-Type: multipart/form-data; boundary=----AptrBoundary

------AptrBoundary
Content-Disposition: form-data; name="image"; filename="photo.jpg"
Content-Type: image/jpeg

<binary image data>
------AptrBoundary
Content-Disposition: form-data; name="user_id"

usr_abc123
------AptrBoundary--

json_base64

La imagen se codifica en base64 y se incluye en un cuerpo JSON junto con metadatos y etiquetas.

{
  "session_id": "sess_01HX...",
  "image_id": "img_01HX...",
  "image_index": 0,
  "mime_type": "image/jpeg",
  "filename": "photo.jpg",
  "size_bytes": 245000,
  "data": "base64-encoded-image-data...",
  "tags": {
    "user_id": "usr_abc123"
  }
}

binary

Los bytes sin procesar de la imagen se envían como cuerpo de la solicitud con Content-Type: application/octet-stream. Los metadatos solo están disponibles en los encabezados.

Verificación de firma HMAC

Cada solicitud de webhook incluye un encabezado X-Aptr-Signature. El valor es sha256=&lt;hex-digest&gt; calculado sobre el cuerpo sin procesar de la solicitud utilizando el secreto de webhook de su proyecto.

Encuentre su secreto de webhook en Panel → Proyecto → Configuración.

const crypto = require("crypto");

function verifySignature(body, signatureHeader, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "utf8"),
    Buffer.from(signatureHeader, "utf8")
  );
}

// Express.js example
app.post("/webhook", express.raw({ type: "*/*" }), (req, res) => {
  const sig = req.headers["x-aptr-signature"];
  if (!verifySignature(req.body, sig, process.env.APTR_WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }
  // Process image...
  res.status(200).end();
});

Nota de seguridad

Siempre lea el cuerpo sin procesar de la solicitud antes de analizarlo. Analizarlo primero (por ejemplo, con un middleware JSON) puede alterar los bytes del cuerpo y causar que la verificación de firma falle.

Política de reintentos

Una entrega de webhook se considera fallida si su servidor devuelve un código de estado diferente a 2xx o no responde dentro de 30 segundos. Las entregas fallidas se reintentan con retroceso exponencial:

IntentoDemora después del anterior
1er reintento30 segundos
2do reintento5 minutos
3er reintento30 minutos
4to reintento2 horas
5to reintento6 horas

Los reintentos adicionales continúan hasta que se agoten los días máximos de reintento del plan. Cuando todos los reintentos fallen, recibirá un correo electrónico de notificación de fallo.