Webhooks — Zkrinet plugin
On Zkrinet: add the block under Building blocks in the panel — one click, your own code is untouched and a snapshot is taken first. The installation steps below apply if you run PocketBase yourself, for example after an export.
When something is created, updated or deleted in your app, a signed request is sent to an address you choose — Slack, Zapier, Make, your own server. Tested against PocketBase 0.40.4. This does not exist in PocketBase.
#Install
Copy pb_hooks/ and pb_migrations/ into the project and restart.
#Add a receiver
In the admin panel, the zk_webhooks collection:
- url — where the request is sent (https)
- samling — the name of the collection, or
*for all - handelser —
create,update,delete - hemlighet — at least 16 characters, used for the signature
- aktiv — check it
#What is sent
POST with JSON:
{ "id": "unikt-id", "handelse": "create", "samling": "anteckningar", "tid": "2026-11-07T06:00:00Z", "post": { ... } }
post is the record as an outsider sees it: hidden fields, passwords and email (unless it is public) are never sent.
#Verify the signature (always do this)
The headers X-Zk-Tid (Unix time) and X-Zk-Signatur (sha256=…). The signature is HMAC-SHA256 with your secret over tid + "." + body:
const vantad = "sha256=" + crypto.createHmac("sha256", HEMLIGHET).update(tid + "." + raKropp).digest("hex")
// compare with X-Zk-Signatur, and reject if tid is older than 5 minutes
The same id can arrive more than once on retries — store the ids you have already handled.
#If the receiver does not respond
The request is made immediately (5-second limit). If the receiver does not respond with 2xx, new attempts are made after 1, 5, 30, 120 and 720 minutes — 6 attempts in total, with exactly the same body. Everything is visible in zk_webhook_logg (delivered / pending / gave up).
#Security
- Requests to private networks are blocked: localhost, 10.x, 172.16–31.x, 192.168.x, 100.64.x, 169.254.x (the cloud metadata service),
.local/.internal, and all IPv6 except ordinary public addresses — including IPv4 disguised as IPv6. Tested against known tricks. - This does not protect against a hostname whose DNS points inward. That protection sits in Zkrinet's firewall, not in the plugin.
- Receivers and log are readable by superuser only.
#Limitations
- The request happens during the save itself: a slow receiver can make the save up to 5 seconds slower.