Skip to content

Webhooks

Webhooks

Izmantojot Webhooks, jūs saņemat reāllaika paziņojumus, kad jūsu Workspace notiek notikumi — piemēram, kad tiek noskenēts QR kods.

Izveidot webhook

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

Atbilde

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

Notikumu veidi

NotikumsApraksts
*Visi notikumi
qr.createdQR kods izveidots
qr.updatedQR kods atjaunināts (URL, statuss, tagi)
qr.deletedQR kods dzēsts
qr.scannedQR kods noskenēts
qr.flaggedQR kods atzīmēts kā nedrošs
webhook.pingTesta ping (izmantojot /ping galapunktu)

Payload formāts

Visiem Webhook payload ir šāds formāts:

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

Koda notikumi: qr.created un qr.updated

Šajos abos notikumos data ir kods tieši tāds, kādu to atgriež GET /v1/codes/:id. Tajā ietilpst appearance — kodam saglabātās krāsas (null nozīmē noklusējuma melno vai balto krāsu):

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

Piemērs ir saīsināts. Visi lauki ir atrodami Kodu API.

Paraksta verifikācija

qr3.app paraksta katru Webhook pieprasījumu ar 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

Verifikācijas ieviešana

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 });
},
);

Atkārtošanas loģika

Kļūdu gadījumā (HTTP >= 300 vai noilgums) qr3.app mēģina veikt piegādi vēlreiz:

MēģinājumsAizture
1Tūlīt
21 minūte
35 minūtes

Pēc 10 pēc kārtas sekojošām kļūdām Webhook tiek automātiski deaktivizēts.

Piegādes garantija

qr3.app piegādā vismaz vienu reizi, nevis tieši vienu reizi. Tāpēc viens un tas pats notikums var sasniegt jūsu galapunktu vairāk nekā vienu reizi: kā atkārtots mēģinājums pēc kļūdas vai kā jau nosūtīta mēģinājuma atkārtojums.

  • Dublikātus atpazīstiet pēc id no payload (evt_…). Tas pieder notikumam un katrā mēģinājumā un katrā atkārtojumā paliek tāds pats. X-QR3-Delivery norāda uz atsevišķu mēģinājumu: šī mēģinājuma atkārtojumam ir tāda pati vērtība, jaunam mēģinājumam — jauna. Jau zināmu id apstipriniet ar 2xx, nevis 4xx: 4xx tiek uzskatīts par neveiksmīgu mēģinājumu, un pēc 10 secīgām kļūdām Webhook tiek automātiski deaktivizēts.
  • Mēģinājums, kas stundu pēc izveides joprojām ir pending (piemēram, tāpēc, ka tā ziņojums rindā ir pazudis), ikdienas tīrīšanā tiek pārslēgts uz failed; status_code un response_time_ms paliek null. Tā nav jūsu galapunkta kļūda, un tā netiek skaitīta starp 10 secīgajām kļūdām. Žurnāls tam saglabā tekstu Delivery was not completed in time — closed by cleanup; piegādes žurnālu galapunkts to neatgriež. Aizvēršana nav galīga: ja ziņojums tomēr atnāk, tas tiek piegādāts un tā faktiskais rezultāts aizstāj šo tekstu.

Piegādes žurnāli

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

Piegādes mēģinājumi tiek glabāti 90 dienas (kārtējā UTC diena un 89 iepriekšējās dienas), pēc tam tie tiek automātiski dzēsti. Papildus parādītajiem laukiem žurnāls glabā notikuma payload un galapunkta atbildes pirmo kilobaitu (1 KB); šis galapunkts neatgriež ne vienu, ne otru.

Testa ping

Testējiet Webhook nekavējoties:

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

Tas nosūta webhook.ping notikumu uz jūsu galapunkta URL.