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
| Encabezado | Descripción |
|---|---|
| X-Aptr-Signature | Firma HMAC-SHA256 del cuerpo de la solicitud |
| X-Aptr-Session-Id | El 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-Id | ID único de la imagen |
| Content-Type | Depende 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=<hex-digest> 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:
| Intento | Demora después del anterior |
|---|---|
| 1er reintento | 30 segundos |
| 2do reintento | 5 minutos |
| 3er reintento | 30 minutos |
| 4to reintento | 2 horas |
| 5to reintento | 6 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.