Webhooks

Webhooks

LifeLoop sends webhook events to notify your application when data changes. Rather than polling the API for updates, you register a webhook URL and receive a notification the moment something happens — a resident is created, an activity is updated, a photo is uploaded.

How it works

1
Event occurs
in LifeLoop
2
LifeLoop sends POST
to your webhook URL with event envelope
3
You verify
the signature
4
You fetch
the full object via the REST API
Payloads are intentionally lightweight.
Each webhook carries only the event type, timestamp, tenant, and the ID of the changed resource. Your application fetches the full object from the corresponding GET endpoint. This keeps payloads small and ensures you always get the freshest data.

Event envelope

Every webhook delivery uses this envelope regardless of event type.

FieldTypeDescription
eventIdstring (UUID)Unique ID for this event. Use for deduplication.
eventTypestringThe event that occurred (see event catalog below).
tenantstringThe tenant this event belongs to.
occurredAtstring (ISO 8601)When the event occurred in LifeLoop.
resourceIdstringID of the resource that changed. Use this to fetch the full object.

Signature verification

Every webhook delivery includes an X-LifeLoop-Signature header. Always verify it before processing the payload.

Always use a timing-safe comparison.
Standard string equality (===) is vulnerable to timing attacks. Use crypto.timingSafeEqual (Node.js) or hmac.compare_digest (Python).

Responding to webhooks

Your endpoint must return an HTTP 200 within 5 seconds. LifeLoop considers any other response (or a timeout) a delivery failure and will retry.

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry8 hours

After 5 failed attempts the event is sent to a dead-letter queue. Contact support to replay failed events.

Event catalog

Event envelopewebhook.json
{
  "eventId": "evt-f3a91bc2-4d12-4e88-a1c3-8f2901dd7c94",
  "eventType": "resident.created",
  "tenant": "sunrise-001",
  "occurredAt": "2026-06-18T10:30:00Z",
  "resourceId": "res-001"
}
Verify signature
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}