Skip to content

Webhooks

Webhooks

B’Webhooks tirċievi notifikazzjonijiet f’ħin reali meta jseħħu avvenimenti fil-Workspace tiegħek — eż. meta jiġi skannjat QR-Code.

Ħolqien ta’ Webhook

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

Rispons

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

Tipi ta’ Avvenimenti

EventDeskrizzjoni
*L-avvenimenti kollha
qr.createdQR-Code maħluq
qr.updatedQR-Code aġġornat (URL, status, tags)
qr.deletedQR-Code imħassar
qr.scannedQR-Code skannjat
qr.flaggedQR-Code mmarkat bħala mhux sigur
webhook.pingPing tat-test (permezz tal-endpoint /ping)

Format tal-Payload

Il-payloads kollha tal-Webhook għandhom dan il-format:

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

Avvenimenti tal-Kodiċi: qr.created u qr.updated

F’dawn iż-żewġ avvenimenti, data hija l-kodiċi eżattament kif ipprovdut minn GET /v1/codes/:id. Dan jinkludi appearance, il-kuluri ffrankati fuq il-kodiċi (null tfisser l-iswed jew l-abjad standard):

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

L-eżempju huwa mqassar. Il-kampi kollha jinsabu fl-API tal-Kodiċijiet.

Verifika tal-Firma

qr3.app jiffirma kull talba (request) ta’ Webhook b’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

Implimenta l-Verifika

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

Loġika ta’ Retry

F’każ ta’ żbalji (HTTP >= 300 jew timeout), qr3.app jipprova jerġa’ jibgħat il-kunsinna:

ProvaDewmien
1Minnufih
2Minuta
35 minuti

Wara 10 żbalji konsekuttivi, il-Webhook jiġi ddiżattivat awtomatikament.

Garanzija tal-Kunsinna

qr3.app jikkunsinna mill-inqas darba, mhux eżattament darba. L-istess avveniment jista’ għalhekk jilħaq l-endpoint tiegħek aktar minn darba: bħala tentattiv mill-ġdid wara żball jew bħala ripetizzjoni ta’ tentattiv li diġà intbagħat.

  • Neħħi d-duplikati bl-użu tal-id tal-payload (evt_…). Jappartjeni lill-avveniment u jibqa’ l-istess f’kull tentattiv u f’kull ripetizzjoni. X-QR3-Delivery jidentifika t-tentattiv individwali: ripetizzjoni ta’ dak it-tentattiv iġorr l-istess valur, tentattiv ġdid iġorr wieħed ġdid. Ikkonferma id li diġà taf b’2xx, mhux b’4xx: 4xx jingħadd bħala tentattiv li falla u, wara 10 żbalji konsekuttivi, il-Webhook jiġi ddiżattivat awtomatikament.
  • Tentattiv li għadu pending siegħa wara li jinħoloq (pereżempju għax il-messaġġ tiegħu fil-kju intilef) jiġi ssettjat fuq failed minn tindif ta’ kuljum; status_code u response_time_ms jibqgħu null. Dan mhuwiex żball tal-endpoint tiegħek u ma jingħadx fost l-10 żbalji konsekuttivi. Il-log jaħżen għalih it-test Delivery was not completed in time — closed by cleanup; l-endpoint tal-logs tal-kunsinna ma jirritornahx. L-għeluq mhuwiex definittiv: jekk il-messaġġ xorta jasal, jiġi kkunsinnat u r-riżultat veru tiegħu jieħu post dak it-test.

Logs tal-Kunsinna

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

It-tentattivi ta’ kunsinna jinżammu għal 90 jum (il-jum UTC kurrenti flimkien mad-89 jum ta’ qabel) u mbagħad jitħassru awtomatikament. Minbarra l-oqsma murija, il-log jaħżen il-payload tal-avveniment u l-ewwel kilobyte (1 KB) tat-tweġiba tal-endpoint; dan l-endpoint ma jirritornax l-ebda wieħed minnhom.

Ping tat-Test

Ittestja Webhook minnufih:

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

Dan jibgħat avveniment webhook.ping lill-URL tal-endpoint tiegħek.