Preskočiť na obsah

Webhooks

Webhooks

S webhookmi prijímate upozornenia v reálnom čase, keď vo vašom workspace nastanú udalosti — napr. keď sa naskenuje QR kód.

Vytvorenie webhooku

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

Odpoveď

{
"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"
}

Typy udalostí

UdalosťPopis
*Všetky udalosti
qr.createdQR kód vytvorený
qr.updatedQR kód aktualizovaný (URL, stav, tagy)
qr.deletedQR kód vymazaný
qr.scannedQR kód naskenovaný
qr.flaggedQR kód označený ako nebezpečný
webhook.pingTestovací ping (cez endpoint /ping)

Formát payloadu

Všetky payloady webhookov majú tento formát:

{
"id": "evt_4f0c2a91d7e84b3c9a1f",
"type": "qr.scanned",
"created": "2026-03-15T10:00:00.000Z",
"data": {
"code_id": "qr_abc123",
"short_code": "r7f3Kx",
"scanned_at": "2026-03-15T10:00:00.000Z",
"country": "AT",
"device_type": "mobile",
"os": "iOS",
"browser": "Safari",
"language": "de",
"ab_variant": null,
"redirected_to": "https://example.com/landing"
}
}

Udalosti kódov: qr.created a qr.updated

Pri týchto dvoch udalostiach je data kód presne taký, ako ho vracia GET /v1/codes/:id. Súčasťou je aj appearance, čo sú farby uložené v kóde (null predstavuje predvolenú čiernu, resp. bielu):

{
"id": "evt_9b2e41c07a5d4f18b3c6",
"type": "qr.updated",
"created": "2026-09-28T10:00:00.000Z",
"data": {
"id": "qr_abc123",
"short_code": "r7f3Kx",
"status": "live",
"appearance": { "foreground_color": "#1F4E79", "background_color": null },
"updated_at": "2026-09-28T10:00:00.000Z"
}
}

Príklad je skrátený. Všetky polia nájdete v API pre kódy.

Overenie podpisu

qr3.app podpisuje každú požiadavku webhooku pomocou HMAC-SHA256:

X-QR3-Signature: sha256=a1b2c3d4e5f6...
X-QR3-Event: qr.scanned
X-QR3-Delivery: wdl_abc123
X-QR3-Attempt: 1
User-Agent: qr3-webhooks/1.0

Implementácia overenia

import crypto from "crypto";
function verifySignature(
payload: string,
signature: string | undefined,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
const expectedBytes = Buffer.from(`sha256=${expected}`);
const receivedBytes = Buffer.from(signature ?? "");
return (
expectedBytes.length === receivedBytes.length &&
crypto.timingSafeEqual(expectedBytes, receivedBytes)
);
}
// In Express: verify the raw body — re-serialised JSON breaks the signature.
app.post(
"/webhooks/qr3",
express.raw({ type: "application/json" }),
(req, res) => {
const raw = req.body.toString("utf8");
const signature = req.headers["x-qr3-signature"] as string | undefined;
if (!verifySignature(raw, signature, process.env.QR3_WEBHOOK_SECRET!)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(raw);
console.log(event.type, event.data);
res.json({ received: true });
},
);

Logika opakovaných pokusov

Pri chybách (HTTP >= 300 alebo vypršaní časového limitu) sa qr3.app pokúsi o doručenie znova:

PokusOneskorenie
1Okamžite
21 minúta
35 minút

Po 10 po sebe nasledujúcich chybách sa webhook automaticky deaktivuje.

Záruka doručenia

qr3.app doručuje aspoň raz, nie presne raz. Tá istá udalosť sa preto môže na váš endpoint dostať viac než raz: ako opakovaný pokus po chybe alebo ako zopakovanie pokusu, ktorý už bol odoslaný.

  • Duplicity odstraňujte podľa id v payloade (evt_…). Patrí k udalosti a zostáva rovnaké pri každom pokuse aj pri každom zopakovaní. X-QR3-Delivery označuje jednotlivý pokus: zopakovanie tohto pokusu nesie rovnakú hodnotu, nový pokus novú. Už známe id potvrďte kódom 2xx, nie 4xx: 4xx sa počíta ako neúspešný pokus a po 10 po sebe nasledujúcich chybách sa webhook automaticky deaktivuje.
  • Pokus, ktorý je hodinu po vytvorení stále pending (napríklad preto, že sa jeho správa vo fronte stratila), denné upratovanie ho nastaví na failed; status_code a response_time_ms zostávajú null. Nejde o chybu vášho endpointu a nezapočítava sa do 10 po sebe nasledujúcich chýb. Záznam preň ukladá text Delivery was not completed in time — closed by cleanup; koncový bod záznamov o doručení ho nevracia. Uzavretie nie je konečné: ak správa napriek tomu dorazí, doručí sa a jej skutočný výsledok tento text nahradí.

Záznamy o doručení

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

Pokusy o doručenie sa uchovávajú 90 dní (aktuálny deň UTC a 89 predchádzajúcich dní) a potom sa automaticky mažú. Okrem zobrazených polí log ukladá payload udalosti a prvý kilobajt (1 KB) odpovede koncového bodu; tento koncový bod nevracia ani jedno z toho.

Testovací ping

Otestujte webhook okamžite:

Terminal window
POST /v1/webhooks/:id/ping

Týmto sa odošle udalosť webhook.ping na adresu URL vášho endpointu.