Account and billing

Webhooks and alerts

Signed webhook deliveries of your account's events, how to verify them, retries, and account alerts by e-mail.

Events

Everything that happens in your account is an event in one ordered, durable stream:

TypeWhen
instance.createdA Kiste was created, forked or restored from a snapshot
instance.runningA Kiste became reachable
instance.stoppedA Kiste stopped; its disk is kept
instance.errorA Kiste crashed or failed to start
instance.deletedA Kiste and its disk were deleted
instance.renamedA Kiste was renamed; data.previous_name has the old name
snapshot.created, snapshot.deletedNamed snapshots and automatic checkpoints
command.started, command.completed, command.failed, command.interrupt_requestedCommands
service.published, service.unpublishedPublished ports on Kiste Stream
api_token.created, api_token.revokedAPI keys
webhook.created, webhook.updated, webhook.deletedWebhook endpoints
alert.raisedAn account alert

Read the stream with kiste events --follow, from the API, or have it delivered to you as webhooks.

Webhooks

A webhook endpoint receives the event types you choose as HTTPS POST requests. Create one in the console under Webhooks, or with POST /v1/webhooks. The signing secret (whsec_…) is shown once, at creation.

Requirements for the URL: HTTPS on port 443, no user name or password in it, and a host that resolves to public addresses. Redirects are not followed.

Every delivery's body is the event:

{ "id": "evt_4107", "object": "event", "sequence": 4107, "type": "instance.running",
  "resource_type": "instance", "resource_id": "…", "data": { "instance_name": "review-42", "status": "running" },
  "created_at": "2026-10-06T08:00:00Z" }

with these headers:

HeaderValue
Kiste-Event-TypeThe event type
Kiste-Event-SequenceThe event's sequence number
Kiste-Delivery-Id, Idempotency-KeyThe delivery's ID
Kiste-Delivery-Attempt1 for the first attempt, then 2, 3, …
Kiste-Signaturet=<unix seconds>,v1=<hex HMAC>

Verify the signature

Compute HMAC-SHA256 over "{t}.{raw body}" with the endpoint's secret, compare it with v1 in constant time, and reject deliveries whose t is more than five minutes old:

verify.js
import crypto from 'node:crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!parts.t || !parts.v1 || age > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected, 'hex');
  const b = Buffer.from(parts.v1, 'hex');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Use the raw request body as it arrived, before any JSON parsing.

Retries and failures

Answer with any 2xx status within 10 seconds. Otherwise the delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. After the sixth failed attempt it is marked failed, the endpoint is marked as failing and a webhook_failing alert is raised. The console shows the last 50 deliveries of each endpoint with their status; Send test event sends a webhook.test delivery right away.

The same event can arrive more than once and out of order. Deduplicate on sequence (or the delivery ID) and order by sequence.

Limits

10 endpoints per account (L07), 32 event types per endpoint, and 20 endpoint changes or test deliveries per minute.

Creating an endpoint raises a webhook_created alert, so an API key that leaked can't quietly add a destination for your events.

Alerts

Alerts tell you about things that need attention. They appear in the console under Alerts, as alert.raised events, and by e-mail to your account's address.

AlertRaised when
instance_errorA Kiste crashed or failed to start
session_not_restoredA saved session couldn't be restored and the Kiste started fresh from its disk
setup_failedAn environment's setup failed; its error is shown only to you
snapshot_failedA checkpoint or snapshot couldn't be taken
disk_almost_fullA running Kiste's disk is 90 % full (cleared below 85 %)
webhook_failingA webhook endpoint keeps failing
webhook_createdA webhook endpoint was created
billing_wallet_empty, billing_machines_parked, billing_auto_refill_failedBilling, once it is active

Alerts never contain output from inside your Kisten. Open alerts of the same kind and cause are collapsed into one until you acknowledge them. Acknowledge an alert in the console when you've dealt with it; choose which kinds are sent by e-mail under Alerts → Email alerts. They stay visible in the console either way.

On this page