Guide to Qlik Cloud Webhooks: Features and Best Practices
Qlik Cloud is Qlik's SaaS platform for analytics apps, data integration and automations. Tenant webhooks report what happens across the tenant, such as an app reload finishing, an automation run failing, an API key failing validation or a user being deleted, so you can trigger downstream jobs, alert on failures or keep an inventory in step.
This guide explains how to create a Qlik Cloud webhook, the supported events and the CloudEvents format, the switch away from legacy fields on December 10, 2026, and how to verify Qlik-Signature.
What are Qlik Cloud webhooks?
A Qlik Cloud webhook is a tenant-level subscription to system events. Tenant admins create them in the Administration activity center, and they can also be created through the Webhooks API or from Qlik Automate. Webhooks made in Qlik Automate show in the activity center but can only be managed from Automate. Each user can own up to 150 webhooks.
Qlik is partway through a format change. Since November 3, 2025, events that weren't already CloudEvents have been sent as hybrids carrying both the CloudEvents fields and the legacy ones. On December 10, 2026 the legacy fields go, and only the CloudEvents form remains.
Qlik Cloud webhook features
| Feature | Details |
|---|---|
| Signature | hex HMAC-SHA256 |
| Signature header | qlik-signature |
| Body | JSON |
| Event routing | Body field type |
From Qlik's webhook administration page:
- The endpoint must be HTTPS and use a domain name, not an IP address.
- An optional secret of 32 to 64 characters adds a
Qlik-Signatureheader. It's write-once and can't be viewed after saving. - Custom headers can be added and encrypted at rest (not in transit). Encrypted headers can be replaced but not edited.
- Check certificate revocation verifies your endpoint's certificate hasn't been revoked.
- The Cloud event option switches the webhook to the new format and can't be undone once saved.
- Delivery history is kept for 7 days, and you can resend an event by clicking its row.
- The example request carries
User-Agent: Qlik WebhookandContent-Type: application/json.
Events and payloads
Route on the CloudEvents type.
| Event routing | Body field type |
Qlik's supported events list has eight more: com.qlik.v1.automation.run.ended, com.qlik.v1.automation.run.failed, the data-integration task events com.qlik.v1.di-projects.di-tasks.started, .stopped, .completed and .failed, com.qlik.analytics.change-store.changes.saved and com.qlik.scheduling.task.updated. qlik.dev documents other system events too, but the help page says its list is what webhooks currently deliver.
A CloudEvents body has id, time, type, source, userid, tenantid, specversion, datacontenttype and data, plus Qlik extensions that vary by event. This is the com.qlik.analytics.change-store.changes.saved example from qlik.dev:
{
"id": "id123",
"time": "2018-10-30T07:06:22Z",
"type": "com.qlik.analytics.change-store.changes.saved",
"source": "com.qlik/write-table",
"userid": "id123",
"tenantid": "id123",
"specversion": "1.0",
"datacontenttype": "application/json",
"data": {
"ownerId": "storeOwner1234",
"spaceId": "space123",
"storeId": "store012",
"tenantId": "tenant123",
"createdBy": "user345",
"committedAt": "2024-01-01T12:20:00Z"
}
}
Hybrid events add eventId, eventTime, eventType, eventTypeVersion, cloudEventsVersion, contentType and extensions. Payloads from before November 2025 carried only eventType, with data under data.attributes. Only 2 of the 22 event types have complete published examples, so capture real deliveries for the ones you handle.
Setting up Qlik Cloud webhooks
- In the Administration activity center, open Webhooks and click Create new.
- Enter a name and the HTTPS endpoint URL, for example
https://example.com/webhooks/qlik-cloud. - Enter a secret of 32 to 64 characters and store it as
QLIK_WEBHOOK_SECRETat the same time, because Qlik won't show it again. - Tick Cloud event if you want the new format now. Leave it until your handler reads
typeif you're unsure, since the choice is permanent. - Under Events, pick from the Automation, API, Application, Data-integration and User groups, then click Create.
To receive through Hookdeck, create a Qlik Cloud source with the same secret and use its URL as the endpoint. Set a secret on the Qlik Cloud webhook. Without one, deliveries are unsigned and fail verification. If you run a webhook without a secret, leave verification off on the source. For local testing:
npx hookdeck-cli listen 3000 qlik-cloud --path /webhooks/qlik-cloud
Securing Qlik Cloud webhooks
With a secret set, Qlik sends Qlik-Signature: the hex HMAC-SHA256 of the raw request body, keyed with the secret's text. It's the bare digest, with no timestamp in the signed content. Qlik's verification guide on qlik.dev shows the same calculation. Don't use the example signature on the help page as a test value: it's 53 hex characters, while a SHA-256 digest is 64.
Node.js verification
const crypto = require('node:crypto');
function verifySignature(rawBody, headers, secret) {
if (!Buffer.isBuffer(rawBody) || typeof secret !== 'string' || !secret) return false;
const signature = headers['qlik-signature'];
if (typeof signature !== 'string') return false;
const key = Buffer.from(secret, 'utf8');
const message = rawBody;
const candidates = [signature];
const expected = crypto.createHmac('sha256', key).update(message).digest();
return candidates.some((candidate) => {
if (!/^[0-9a-fA-F]{64}$/.test(candidate)) return false;
const received = Buffer.from(candidate, 'hex');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
});
}
HTTP method
Qlik's docs say a webhook sends "an HTTP JSON request" but never name the method. Hookdeck's Qlik Cloud source pre-selects POST without managing the method, so add other methods on the source if you see them arrive. The receiver below uses app.all and verifies whatever method comes in, treating a missing body as empty bytes.
const express = require('express');
const app = express();
app.all('/webhooks/qlik-cloud', express.raw({ type: '*/*' }), async (req, res) => {
const secret = process.env.QLIK_WEBHOOK_SECRET;
if (!secret) return res.sendStatus(500);
const body = Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0);
if (!verifySignature(body, req.headers, secret)) return res.sendStatus(401);
if (!body.length) return res.sendStatus(200);
let event;
try {
event = JSON.parse(body.toString('utf8'));
} catch {
return res.sendStatus(400);
}
if (!event || typeof event !== 'object' || Array.isArray(event)) return res.sendStatus(400);
const type = event.type ?? event.eventType;
if (typeof type !== 'string') return res.sendStatus(400);
try {
if (type === 'com.qlik.v1.reload.finished' || type === 'com.qlik.v1.app.reload.finished') {
await queue.add('qlik-reload', { id: event.id ?? event.eventId, type, data: event.data });
} else if (type.endsWith('.failed')) {
await alerts.send({ type, tenant: event.tenantid, data: event.data });
}
} catch {
return res.sendStatus(503);
}
res.sendStatus(200);
});
The fallback to eventType only matters for hybrid or older payloads. After December 10, 2026, type is the only one present.
Hookdeck's Qlik Cloud source checks the same HMAC. It returns 200 to Qlik and records any mismatch as failed verification instead of rejecting it. Qlik signs no timestamp, and Hookdeck applies no time window.
Make Qlik Cloud webhooks production-ready. Hookdeck Event Gateway keeps Qlik events well beyond Qlik's 7-day history, with retries and bulk replay when your service has been down.
Qlik Cloud webhook limitations and pain points
Legacy fields disappear on December 10, 2026
The Problem: Handlers that read eventType, eventId or eventTime will stop working when the legacy fields are removed.
Why It Happens: Qlik has been sending hybrid payloads since November 3, 2025, and its changelog moved the removal date from October 6 to December 10, 2026. After that, only CloudEvents fields such as type, id and time are sent.
Workarounds:
- Switch your code to
type,idandtimenow, keeping legacy fields only as a fallback. - Tick Cloud event on a test webhook first to see CloudEvents-only payloads before the cut-over.
How Hookdeck Can Help: Hookdeck's request log shows the exact payloads Qlik is sending, so you can compare hybrid and CloudEvents-only bodies side by side, and a transformation can map legacy field names while you migrate.
Retries are undocumented
The Problem: You can't tell whether Qlik retries a failed delivery, or how long it waits for a response.
Why It Happens: Qlik documents a 7-day history with manual resend, but no timeout, retry policy or ordering guarantee.
Workarounds:
- Check the webhook history after any outage and resend failed deliveries by hand within 7 days.
- Reply quickly and process reloads and alerts in the background.
How Hookdeck Can Help: Hookdeck accepts each event, keeps it, and retries your service automatically, so recovery doesn't depend on someone clicking resend.
Signatures are optional and secrets are write-once
The Problem: A webhook created without a secret sends unsigned requests, and a lost secret can't be recovered.
Why It Happens: The secret field is optional, and Qlik never shows a saved secret again.
Workarounds:
- Always set a secret, and save it in your secret store before clicking Create.
- To rotate, edit the webhook, enter a new secret and update your receiver at the same time.
How Hookdeck Can Help: Hookdeck records requests that fail verification, so a mismatch after a secret change shows up in the log instead of disappearing.
Most event payloads aren't published
The Problem: You can't write a handler from documentation alone for most events.
Why It Happens: Complete examples exist for 2 of the 22 types. Others use "string" placeholders or the legacy format, and qlik.dev names several app events differently from the webhook list.
Workarounds:
- Subscribe a test webhook and capture one real delivery for each event you need.
- Validate fields before reading them, and log unknown types.
How Hookdeck Can Help: Hookdeck stores every request body, giving you real examples to build and test against.
Best practices
Turn on Cloud event deliberately
The switch is permanent per webhook. Update your handler first, then enable it, or create a new webhook with it on and retire the old one.
Deduplicate on the event id
Use id (or eventId on older payloads) as the deduplication key, since a manual resend can deliver the same event again. More on making webhook handlers idempotent.
Hand reloads to a queue
Reload and data-integration events usually start longer jobs. Acknowledge first and run them from a queue. The reasons are in our guide to asynchronous webhook processing.
Prefer encrypted headers for extra credentials
If your endpoint needs a bearer token as well as the signature, add it as an encrypted custom header so it isn't stored in plain text in Qlik.
Conclusion
Qlik Cloud webhooks deliver tenant events as CloudEvents, signed with a hex HMAC-SHA256 in Qlik-Signature when you set a secret. The pressing task is the December 10, 2026 removal of legacy fields. After that, the gaps to plan around are the undocumented retries and HTTP method and the 7-day history.
Hookdeck Event Gateway verifies Qlik's signature, holds events for as long as you need them and retries delivery to your services.
Get started with Hookdeck for free and handle Qlik Cloud webhooks reliably in minutes.