Signed webhooks
Partners with an API key can register an https URL and a list of tracked projects. When a project's public record changes, we POST a JSON event signed with the same Ed25519 key and scheme as the open API, timestamped and safe against replay. Every attempt is logged where you can see it.
Checking status…
A real signed event, verified in your browser
This is a sample event signed just now by our server with the production key. Your browser fetches the public key from /.well-known/kolaboro-keys.json and checks the signature with WebCrypto.
Loading a signed sample…
What we send
POST to your URL with content-type: application/json, a 10 second timeout and no redirects followed. Any 2xx answer counts as delivered.
| Header | Meaning |
|---|---|
x-kolaboro-signature | Base64 Ed25519 signature over "kolaboro-sig-v1\n" + SHA-256 hex of the exact body. Same scheme as every open API answer. |
x-kolaboro-key-id | Which key signed it. Public keys at /.well-known/kolaboro-keys.json. |
x-kolaboro-timestamp | Unix seconds of this attempt. The same value is inside the signed body as timestamp; trust the body. |
x-kolaboro-event, x-kolaboro-event-id | Event type and id, copied from the body for routing. |
x-kolaboro-delivery-attempt | 1 for the first attempt, then 2, 3 and so on. |
Events are computed once a day after the research agent's run, with the same change detection as the push alerts: public checks, deposit protection and permit status, stage, reported delay, independent confirmations, satellite and register status, and changes on the developer's own page. The first time we see a project we only record its state, so your first event comes on its first real change. A ping event is sent when you register and whenever you press "Send a ping".
Verify every delivery
Four checks, in this order: the signature over the raw body, the timestamp within 5 minutes, the webhook_id is yours, and the event id is new to you. Read the raw body before parsing JSON: re-serialising changes the bytes and breaks the signature.
JavaScript (Node 20+, Deno, Bun, Workers, browsers)
verify.mjs, WebCrypto only, no dependencies.
Python
verify.py, needs pip install cryptography.
Both files were tested against a local receiver: genuine deliveries pass, and an edited body, a replayed event, a stale timestamp and an event for another webhook are refused.
Retries and the delivery log
- Up to 3 attempts during the run, 2 and 6 seconds apart, unless you answer with a 4xx other than 408 or 429 (those will not change on retry).
- Still failing: the next daily runs try again, up to 6 attempts over 3 days, with a new timestamp and signature each time and the same event id.
- After 20 failed deliveries in a row the webhook is switched off. Registering the same URL again switches it back on.
- Every attempt is logged with status code, time taken and error. The holder of the key sees the last 100 below. We keep the event body only for deliveries that failed, so they can be retried.
Register, test and see deliveries
No key yet? Create one in a few seconds. The key is sent only in the x-api-key header and kept in this tab's memory. The URL must be public https on port 443, without an IP address or credentials. Up to 5 webhooks per key and 200 projects per webhook.