Skip to content

Webhooks

Webhooks

S spletnimi kljukami (webhooks) prejemate obvestila v realnem času, ko se v vaši delovni površini (workspace) zgodijo dogodki — npr. ko je skenirana QR-koda.

Ustvarjanje spletne kljuke

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

Odgovor

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

Vrste dogodkov

DogodekOpis
*Vsi dogodki
qr.createdQR-koda ustvarjena
qr.updatedQR-koda posodobljena (URL, status, oznake)
qr.deletedQR-koda izbrisana
qr.scannedQR-koda skenirana
qr.flaggedQR-koda označena kot nevarna
webhook.pingTestni ping (preko končne točke /ping)

Format podatkov (Payload)

Vsi podatki spletnih kljuk (payloads) imajo naslednjo obliko:

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

Dogodki kode: qr.created in qr.updated

Pri teh dveh dogodkih je data koda natanko takšna, kot jo vrne GET /v1/codes/:id. To vključuje appearance, barve, shranjene v kodi (null predstavlja privzeto črno oziroma belo):

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

Primer je skrajšan. Vsa polja so na voljo v API-ju za kode.

Preverjanje podpisa

qr3.app vsako zahtevo spletne kljuke podpiše s 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

Implementacija preverjanja

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 ponovnih poskusov

V primeru napak (HTTP >= 300 ali časovna omejitev) qr3.app ponovno poskusi z dostavo:

PoskusZakasnitev
1Takoj
21 minuta
35 minut

Po 10 zaporednih napakah se spletna kljuka samodejno onemogoči.

Zagotovilo o dostavi

qr3.app dostavlja vsaj enkrat, ne natančno enkrat. Isti dogodek lahko zato na vašo končno točko prispe večkrat: kot ponovni poskus po napaki ali kot ponovitev poskusa, ki je bil že poslan.

  • Podvojene dogodke odpravite s poljem id v payloadu (evt_…). Pripada dogodku in ostane enak pri vsakem poskusu in vsaki ponovitvi. X-QR3-Delivery označuje posamezen poskus: ponovitev tega poskusa nosi isto vrednost, nov poskus novo. Že znani id potrdite s kodo 2xx, ne s 4xx: 4xx se šteje kot neuspel poskus, po 10 zaporednih napakah pa se spletna kljuka samodejno onemogoči.
  • Poskus, ki je uro po ustvarjanju še vedno pending (na primer ker se je njegovo sporočilo v čakalni vrsti izgubilo), ga dnevno čiščenje nastavi na failed; status_code in response_time_ms ostaneta null. To ni napaka vaše končne točke in se ne všteva med 10 zaporednih napak. Dnevnik zanj shrani besedilo Delivery was not completed in time — closed by cleanup; končna točka za dnevnike dostave ga ne vrne. Zaprtje ni dokončno: če sporočilo vseeno prispe, se dostavi, njegov dejanski rezultat pa to besedilo nadomesti.

Dnevniki dostave

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

Poskusi dostave se hranijo 90 dni (tekoči dan UTC in 89 prejšnjih dni), nato se samodejno izbrišejo. Poleg prikazanih polj dnevnik shranjuje payload dogodka in prvi kilobajt (1 KB) odgovora končne točke; ta končna točka ne vrača nobenega od obeh.

Testni ping

Takoj preizkusite spletno kljuko:

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

To pošlje dogodek webhook.ping na vaš URL končne točke.