Webhooks — event notifications to your own systems
Webhooks let VAREK automatically push event notifications to your own systems as HTTP POST requests. Instead of your system polling the API, VAREK calls your server whenever something important happens.
Webhooks are useful for, for example:
- alerting other systems automatically when a claim deadline approaches,
- logging new defects or claims into an external system,
- synchronising status changes to property management software.
:::note Board admin only. Webhook management is visible only to the housing company’s board admin under Asetukset → Webhookit (Settings → Webhooks). :::
Creating an endpoint
Section titled “Creating an endpoint”- Sign in as a board admin.
- Go to Asetukset → Webhookit (Settings → Webhooks).
- Click Lisää päätepiste (Add endpoint).
- Enter the endpoint URL — it must be a public
https://address with a domain name (IP-address hosts are rejected). - Select the events you want to be notified about (see the event catalogue below).
- Confirm. VAREK automatically generates a signing secret (
whsec_…).
:::caution The secret is shown only once.
Copy the whsec_… secret immediately after creation. It cannot be retrieved
again. If the secret is lost, you can reveal it again under
Endpoint details → Show secret (admin only).
:::
Event catalogue
Section titled “Event catalogue”| Event | When it fires | data fields |
|---|---|---|
claim.deadline_approaching | A claim deadline is approaching | claim_id, deadline_id, days_until |
claim.created | A new claim was created | claim_id, claim_number |
claim.status_changed | A claim’s status changed | claim_id, status, previous_status |
defect.created | A new defect report was created | defect_id |
document.uploaded | A new document was added | document_id |
inspection.completed | An inspection was marked complete | inspection_id, template_key |
invoice.paid | A resident invoice was settled | invoice_id, invoice_type |
board_initiative.created | A board decision or assignment was created | initiative_id, category |
board_initiative.decided | A board decision was reached (approved or rejected) | initiative_id, outcome |
board_initiative.assigned | An assignee was added to an assignment | initiative_id, assignee_id, target_kind, role_label |
board_initiative.completed | An assignment was marked done | initiative_id |
Delivery envelope (JSON body)
Section titled “Delivery envelope (JSON body)”Every delivery is a POST request whose body is a JSON object:
{ "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "type": "claim.status_changed", "created_at": "2026-06-30T08:00:00Z", "data": { "claim_id": "...", "status": "closed", "previous_status": "open" }}| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier for this delivery |
type | string | Event name (see catalogue) |
created_at | ISO 8601 | Event timestamp (UTC) |
data | object | Event details (ID references) |
Payloads are thin — they contain IDs only. Fetch full details from the REST API as needed.
Verifying the signature
Section titled “Verifying the signature”VAREK signs every delivery with HMAC-SHA256 using the endpoint’s whsec_…
secret. Two HTTP headers are sent with each delivery:
| Header | Value |
|---|---|
X-Vrk-Signature | Signature in lowercase hex |
X-Vrk-Timestamp | Timestamp in Unix seconds (string) |
Signature formula: HMAC-SHA256(rawBody + timestamp, signing_secret) →
lowercase hex. The signed value is the raw HTTP request body string
concatenated with the timestamp string.
Node.js example:
import crypto from 'node:crypto';
// raw = the EXACT raw request body bytes/string;// do not re-serialize the JSONfunction verify(signingSecret, rawBody, headers) { const ts = headers['x-vrk-timestamp']; const sig = headers['x-vrk-signature']; // reject stale deliveries (replay protection) if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; const expected = crypto .createHmac('sha256', signingSecret) .update(rawBody + ts) .digest('hex'); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));}:::caution Use the raw body. Never parse and re-serialize the JSON body before computing the signature — reformatting JSON changes the bytes and the signature will not match. Read the raw HTTP body before parsing. :::
Ready-made helper (@varek/sdk)
Section titled “Ready-made helper (@varek/sdk)”The easiest path is the official @varek/sdk
package’s constructWebhookEvent, which verifies the signature
(constant-time comparison), checks the timestamp (default 300 s window) and
parses the envelope in one call:
import { constructWebhookEvent, VarekWebhookError } from '@varek/sdk';
const event = await constructWebhookEvent({ secret: process.env.VAREK_WEBHOOK_SECRET, rawBody, // the raw body string signature: headers['x-vrk-signature'], timestamp: headers['x-vrk-timestamp'],});// event = { id, type, created_at, data } — respond 400 on VarekWebhookErrorThe package also exports the WEBHOOK_EVENTS catalog and types. The full
event catalog is machine-readable in the
OpenAPI specification’s webhooks
section as well.
Retries and backoff
Section titled “Retries and backoff”VAREK retries a delivery if your server does not respond with a 2xx status code or times out. Up to 6 attempts are made with exponential backoff (30 s, 60 s, 120 s … capped at approximately 1 h).
A delivery that exhausts all attempts is marked as failed.
Delivery log and Replay
Section titled “Delivery log and Replay”Under Asetukset → Webhookit → [endpoint] → Toimitukset (Deliveries) you can see the full delivery history for that endpoint: timestamp, event type, HTTP status code, and any error message.
You can replay any delivery with the Toista (Replay) button. A replay
sends the same original JSON body again with a fresh X-Vrk-Timestamp and
X-Vrk-Signature — the id remains the same.
Revealing the secret again
Section titled “Revealing the secret again”If the whsec_… secret is lost, a board admin can reveal it under
Asetukset → Webhookit → [endpoint] → Näytä salaisuus (Show secret). The
secret does not rotate automatically — only creating a new endpoint or manually
rotating it generates a new secret.