Skip to content

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). :::

  1. Sign in as a board admin.
  2. Go to Asetukset → Webhookit (Settings → Webhooks).
  3. Click Lisää päätepiste (Add endpoint).
  4. Enter the endpoint URL — it must be a public https:// address with a domain name (IP-address hosts are rejected).
  5. Select the events you want to be notified about (see the event catalogue below).
  6. 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). :::

EventWhen it firesdata fields
claim.deadline_approachingA claim deadline is approachingclaim_id, deadline_id, days_until
claim.createdA new claim was createdclaim_id, claim_number
claim.status_changedA claim’s status changedclaim_id, status, previous_status
defect.createdA new defect report was createddefect_id
document.uploadedA new document was addeddocument_id
inspection.completedAn inspection was marked completeinspection_id, template_key
invoice.paidA resident invoice was settledinvoice_id, invoice_type
board_initiative.createdA board decision or assignment was createdinitiative_id, category
board_initiative.decidedA board decision was reached (approved or rejected)initiative_id, outcome
board_initiative.assignedAn assignee was added to an assignmentinitiative_id, assignee_id, target_kind, role_label
board_initiative.completedAn assignment was marked doneinitiative_id

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"
}
}
FieldTypeDescription
idUUIDUnique identifier for this delivery
typestringEvent name (see catalogue)
created_atISO 8601Event timestamp (UTC)
dataobjectEvent details (ID references)

Payloads are thin — they contain IDs only. Fetch full details from the REST API as needed.

VAREK signs every delivery with HMAC-SHA256 using the endpoint’s whsec_… secret. Two HTTP headers are sent with each delivery:

HeaderValue
X-Vrk-SignatureSignature in lowercase hex
X-Vrk-TimestampTimestamp 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 JSON
function 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. :::

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 VarekWebhookError

The 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.

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.

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.

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.