Sending events
How to reach Litehook, what to send, and what comes back.
Source addresses
New sources use signed requests unless you turn signing off when you create them. A URL token source accepts events two ways. Both take the same JSON body.
| Use | Source address |
|---|---|
| Services that only take a URL | POST https://litehook.app/hook/SOURCE_ID/SOURCE_SECRET |
| Your own code | POST https://litehook.app/api/ingest/SOURCE_ID with Authorization: Bearer SOURCE_SECRET |
Send Content-Type: application/json. The /hook address holds the secret. Keep it private.
Signed requests
A signed source has one source address, POST https://litehook.app/api/v1/sources/SOURCE_ID/events, and a signing secret that starts with whsec_. Each request carries three Standard Webhooks headers:
| Header | Value |
|---|---|
webhook-id | A unique ID for this event. A retry reuses it and isn't stored twice. |
webhook-timestamp | Seconds since 1970. Must be within 5 minutes of now; a source can set 30 seconds to 15 minutes. |
webhook-signature | v1, then the base64 HMAC-SHA256 of ID.TIMESTAMP.BODY, keyed with the base64-decoded secret after whsec_. |
Most languages have a Standard Webhooks library that signs for you. From a shell:
export LITEHOOK_SECRET='whsec_…'
BODY='{"title":"Hello from my app","level":"success"}'
ID="msg_$(date +%s%N)"; TS=$(date +%s)
KEY=$(printf '%s' "${LITEHOOK_SECRET#whsec_}" | base64 -d | od -An -tx1 | tr -d ' \n')
SIG=$(printf '%s' "$ID.$TS.$BODY" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$KEY" -binary | base64)
curl -X POST 'https://litehook.app/api/v1/sources/SOURCE_ID/events' \
-H 'Content-Type: application/json' \
-H "webhook-id: $ID" -H "webhook-timestamp: $TS" -H "webhook-signature: v1,$SIG" -d "$BODY"
Signed sources also accept plain text and form data. For senders that can’t sign, such as Coolify or Home Assistant, use a URL token source.
Fields
| Field | Type | Notes |
|---|---|---|
title | text, up to 120 | The notification's headline. Falls back to event, then the source name. |
message | text, up to 2,000 | Optional detail. body is accepted too. |
level | info, success, warning, error | Defaults to info. Warnings and errors are labelled in the inbox. |
success | true or false | Sets the level to success or error when level is not given. |
group | text, up to 80 | Collapses repeats. See Grouping. |
idempotency_key | text, up to 120 | URL token sources: marks a repeat as a duplicate. See Duplicates. |
Title and message are trimmed to fit. Unknown fields are ignored.
Grouping
Give related events from one source the same group to get one notification instead of many. In the inbox they collapse into the latest event with a count, like Disk at 92% ×3. On your phone each new one replaces the previous notification.
{"title":"Disk at 92%","level":"warning","group":"disk-space"}
Opening a grouped notification marks the whole group read.
Duplicates
A signed request is identified by its webhook-id for 7 days: a retry with the same ID and body is accepted but not saved again, and the response includes "duplicate": true. The same ID with a different body is refused with 409. For a URL token source, an Idempotency-Key header works the same way. An idempotency_key field marks any repeat as a duplicate, without the 409.
Responses and errors
| Status | Meaning |
|---|---|
202 | Accepted. Signed sources answer {"accepted":true,"event_id":"…","duplicate":false}; URL token sources answer {"accepted":true,"id":123,"event_id":"…"}, or "duplicate":true for a repeat. |
400 | The body cannot be parsed, or a field is invalid. The error says which. |
401 | The secret or signature is wrong, missing or out of date, or the source does not exist. On URL token sources, a disabled or deleted source gets the same answer. |
403 | The workspace is paused, or the sender's IP address is not on the source's allowlist. |
404 | Wrong URL: extra path segments, or a workspace address instead of litehook.app. |
409 | A signed source that has never been published, or an event ID reused with a different body. |
410 | A signed source with receiving turned off. |
413 | The body is over 64 KiB. |
415 | The content type is not accepted: application/json for URL token sources; JSON, plain text or form data for signed sources, as the source allows. |
422 | The body does not match the source's payload schema. |
429 | Too many events: over 300 a minute for one source or 1,200 for a workspace or IP address, the source is cooling off, or 1.5× the monthly allowance is used. Wait for Retry-After when given. |
503 | Busy. Retry after Retry-After. |
508 | The event looped through Litehook 3 times. |
Your phone's operating system decides when a notification is shown, so test a source before relying on it for urgent alerts.