LilliaIntegration documents www.lilliacare.ai

Client webhooks

Lillia notifies your system with one signed HTTPS message when something changes for your members, for example a completed journey. Register an endpoint, verify the signature, reply 2xx.

Version 1.1 · Last updated 28 October 2026

Lillia can notify your system automatically when something changes for your members, for example when a member completes a journey. Each update is one signed HTTPS message to an address you choose. Staging and Production are set up separately, each with its own address and signing secret.

How it works, end to end

A. Set-up, once per environment (Staging, then Production)

  1. You send us your HTTPS endpoint URL and a contact mailbox
  2. Lillia registers it and shares the signing secret with you securely
  3. Lillia sends a test a signed ping message to your endpoint
  4. You confirm signature verified, replied HTTP 200

B. Live, for every update you selected

  1. Something changes for example a member completes a journey on Lillia
  2. Lillia sends one message a signed HTTPS POST to your endpoint
  3. You verify and reply check the signature, answer 2xx within 10 seconds
  4. Delivered logged for 30 days, same id on every retry. No 2xx: Lillia retries, up to 8 attempts over about 46 hours

Who shares what

You share with Lillia, per environment Lillia shares with you, per environment
Your HTTPS endpoint URL (https:// only; no redirects; no username and password) The signing secret (whsec_…), shown once, sent through an agreed secure channel
A technical contact mailbox for delivery notices A test message so you can confirm your set-up
The updates you want (see the list below) The message format and the delivery rules on this page
Whether you need our source IP addresses for an allow-list A delivery log we can share on request (30 days)

What a message looks like

Request from Lillia (headers):

POST /hooks/lillia HTTP/1.1
Host: api.your-system.example
content-type: application/json
user-agent: Lillia-Webhooks/1
lillia-event-type: journey.completed
webhook-id: whd_2f8c1e9a-…
webhook-timestamp: 1762161262
webhook-signature: v1,K5oZ3n0k6yQ1yYH1g5a3cXl7xM2wR9pT4uV6bN8dE0s=

The four headers that matter:

Header Meaning
lillia-event-type The update type, the same value as type in the body, so you can route before parsing
webhook-id The delivery id. Stable across every retry of the same message; use it to discard repeats.
webhook-timestamp When the message was sent, as Unix seconds
webhook-signature v1, followed by the Base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body} with your secret. Two values, space separated, during a secret rotation; accept if either matches.

Body (example: a journey completed):

{
  "id": "evt_7d5f4a1e-…",
  "type": "journey.completed",
  "occurred_at": "2026-11-03T09:14:22Z",
  "tenant_id": "your-tenant-id",
  "data": {
    "user_journey_id": "c3a9…",
    "journey_id": "8e21…",
    "patient_id": "a71d…",
    "program_id": "19f4…",
    "status": "completed",
    "previous_status": "in_progress",
    "completed_at": "2026-11-03T09:14:22Z",
    "completion_mode": "automatic"
  }
}

Your response (any 2xx within 10 seconds; body optional):

HTTP/1.1 200 OK
content-length: 0

How you verify the signature (Standard Webhooks format; libraries exist for most languages):

key      = base64_decode(secret without the "whsec_" prefix)
signed   = webhook_id + "." + webhook_timestamp + "." + raw_body
expected = base64(hmac_sha256(key, signed))
accept if constant_time_equal(expected, signature after "v1,")
      and abs(now - webhook_timestamp) <= 300 seconds

Every message has the same outer fields: id, type, occurred_at, tenant_id and data. The data object holds identifiers and statuses for the update; never names, contact details or clinical data. Further detail is read by identifier through the Lillia API.

Updates available

Group Updates
Journeys journey.completed · journey.enrolled · journey.exited
Appointments appointment.booked · appointment.rescheduled · appointment.cancelled · appointment.completed · appointment.no_show
Subscriptions subscription.activated · subscription.renewed · subscription.past_due · subscription.expired · subscription.cancelled
Programs program.changed

The same registration covers all of them. Updates can be added later without a new endpoint.

Delivery rules

Rule Detail
Acknowledgement Any HTTP 2xx within 10 seconds. Redirects are not followed.
Retries Up to 8 attempts over about 46 hours: immediately, then after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours
Duplicates and order Possible after a retry. Discard repeats by webhook-id; use occurred_at, not arrival order.
Timestamp check Reject a message whose webhook-timestamp is more than 5 minutes from your clock
Stopping A 410 Gone reply stops deliveries at once. After 3 days of failed deliveries the endpoint is paused and your contact is informed.
Secret rotation On request. For 24 hours each message carries two signatures, space separated, so you can switch without interruption.
Source IP addresses Authenticity comes from the signature. If your policy requires an allow-list, tell us and we confirm the addresses before go-live.
Changes to the format New fields may be added at any time; ignore fields you do not know. Lillia gives 30 days' notice of any change that is not backward compatible.

Getting started

  1. Send us, for Staging: your endpoint URL, a contact mailbox and the updates you want. Reach your Lillia account contact or write to us through www.lilliacare.ai.
  2. We register the address, share the signing secret securely and send a test message.
  3. You confirm the test and exercise the updates you need on Staging with test data.
  4. Send the same details for Production. We register it, send a test, and live updates start on the agreed date.

Changes to an address, the updates or a secret are requested through your Lillia account contact.

Downloads