Skip to content
Reference

Webhook payloads

The five events Kōlea posts to your endpoints, what each body holds, and how to check the signature.

A webhook tells your own systems when something happens in Kōlea: someone joins or leaves, a hard bounce, a sale, a published post. You add an endpoint under Settings > Webhooks, pick its events, and Kōlea posts JSON to it each time one happens. This page is the contract your developer codes against.

The request

Every delivery is a POST with a JSON body and these headers:

HeaderValue
Content-Typeapplication/json
User-AgentKolea-Webhooks/1
Kolea-EventThe event type, such as subscribed.
Kolea-Event-IdThe event's id. The same on every retry.
Kolea-Delivery-Attempt1 for the first try, then 2, 3 ...
Kolea-Signaturet=<unix seconds>,v1=<hex>

The body is the same bytes on every attempt:

{
  "id": "the event's id",
  "type": "purchased",
  "created_at": "2026-10-10T14:03:00Z",
  "data": { ... }
}

The events

TypeWhendata
subscribedSomeone new joins, confirms their opt-in, or resubscribes.subscriber, and via (subscribed, promoted, or resubscribed)
unsubscribedSomeone leaves broadcasts or everything.subscriber, and scope (broadcasts or everything)
bouncedA hard bounce.subscriber, and bounce (hard)
purchasedA paid sale is recorded.subscriber and sale
publishedA post goes on your site.post

A subscriber is token, email, name, status, source, and subscribed_at. A sale is token, amount (in minor units, so 4100 is 41.00), currency, description, source, and occurred_at. A post is token, slug, title, url, and published_at. Times are ISO 8601 in UTC.

Check the signature

  1. Read the raw request body before parsing it.
  2. Split Kolea-Signature on commas into t and v1.
  3. Compute HMAC-SHA256 of t, a dot, and the raw body, using the endpoint's signing secret (it starts whsec_). Hex-encode it in lowercase.
  4. Compare it with v1 in constant time.
  5. Reject the request if t is more than five minutes from your clock.

Retries

Any 2xx answer within 10 seconds counts as delivered. Anything else is tried again, up to 8 attempts in all, waiting 30 seconds, then 2 minutes, then 8, and so on up to 6 hours between tries. Every attempt, with its status code and the start of your reply, is in the endpoint's delivery log.

Things to know

  • Use Kolea-Event-Id to ignore a delivery you already handled; a retry carries the same id.
  • Imports and backfills send no events, and neither does a sale that arrived by import.
  • After 15 failed deliveries in a row the endpoint is switched off, with the reason shown. Switch it back on once it answers.
  • Endpoints must be https on a public host.
  • The signing secret is shown once, when you create the endpoint.