Saltearse al contenido

Webhooks

Webhooks

Con los webhooks recibes notificaciones en tiempo real cuando ocurren eventos en tu workspace; por ejemplo, cuando se escanea un código QR.

Crear un webhook

Ventana de terminal
POST /v1/webhooks
{
"url": "https://example.com/webhooks/qr3",
"events": ["qr.scanned", "qr.created"],
"secret": "my-secret-key-min-16-chars"
}

Respuesta

{
"id": "wh_abc123",
"url": "https://example.com/webhooks/qr3",
"events": ["qr.scanned", "qr.created"],
"is_active": true,
"secret": "my-secret-key-min-16-chars",
"secret_hint": "my-s…",
"created_at": "2026-03-15T10:00:00.000Z"
}

Tipos de eventos

EventDescripción
*Todos los eventos
qr.createdCódigo QR creado
qr.updatedCódigo QR actualizado (URL, estado, etiquetas)
qr.deletedCódigo QR eliminado
qr.scannedCódigo QR escaneado
qr.flaggedCódigo QR marcado como no seguro
scan.createdEvento de escaneo (alias de qr.scanned)
workspace.updatedWorkspace actualizado
webhook.pingPing de prueba (a través del endpoint /ping)

Formato del payload

Todos los payloads de los webhooks tienen este formato:

{
"id": "evt_abc123xyz",
"type": "qr.scanned",
"created": "2026-03-15T10:00:00.000Z",
"data": {
"code_id": "qr_abc123",
"short_code": "r7f3Kx",
"scan_id": "scn_xyz",
"country": "AT",
"device_type": "mobile",
"os": "iOS"
}
}

Verificación de firmas

qr3.app firma cada solicitud de webhook con HMAC-SHA256:

X-QR3-Signature: sha256=a1b2c3d4e5f6...

Implementar la verificación

import crypto from "crypto";
function verifySignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
const received = signature.replace("sha256=", "");
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(received, "hex")
);
}
// In Express:
app.post("/webhooks/qr3", (req, res) => {
const signature = req.headers["x-qr3-signature"] as string;
const valid = verifySignature(
JSON.stringify(req.body),
signature,
process.env.QR3_WEBHOOK_SECRET
);
if (!valid) return res.status(401).json({ error: "Invalid signature" });
const event = req.body;
console.log(event.type, event.data);
res.json({ received: true });
});

Lógica de reintentos

En caso de errores (HTTP >= 300 o tiempo de espera agotado), qr3.app intentará entregar el mensaje de nuevo:

IntentoRetraso
1De inmediato
21 minuto
35 minutos

Después de 10 errores consecutivos, el webhook se desactivará automáticamente.

Registros de entrega

Ventana de terminal
GET /v1/webhooks/:id/deliveries
{
"data": [
{
"id": "whd_abc123",
"event_type": "qr.scanned",
"status": "success",
"status_code": 200,
"response_time_ms": 145,
"attempt": 1,
"created_at": "2026-03-15T10:00:00.000Z"
}
]
}

Ping de prueba

Prueba un webhook de inmediato:

Ventana de terminal
POST /v1/webhooks/:id/ping

Esto envía un evento webhook.ping a la URL de tu endpoint.