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 check
the X-API-KEY header
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).
aggregateTypestringDomain of the affected resource (e.g. resident, activity, notification).
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.

Authenticating deliveries

Every delivery carries your integration's configured key in the X-API-KEY header. Check it before trusting the request. If no key is configured for your tenant, the header is not sent.

Compare keys in constant time.
Use crypto.timingSafeEqual (Node.js) or hmac.compare_digest (Python) rather than plain string equality.

Responding to webhooks

Any 2xx response means the event was delivered; the body is ignored. LifeLoop waits up to 5 seconds to connect and 10 seconds for a response.

A delivery is retried when there is no response (connection error or timeout) or the response is 5xx, 408 or 429. Any other response, including 3xx redirects and other 4xx codes, is final.

AttemptDelay after previous
Initial delivery—
1st retry~30 seconds
2nd retry~1 minute
3rd retry~2 minutes
4th retry~4 minutes
Duplicates and ordering.
A retry resends the same event with the same eventId — use it to skip events you have already processed. Delivery order is not guaranteed: order events by occurredAt and treat each event as a signal to re-read the resource.

Event catalog

resident.createdresident.updatedresident.deleted

A resident record was created, updated, or removed

View details →
connection.createdconnection.updatedconnection.deleted

A family member or connection was added, updated, or removed

View details →
activity.createdactivity.updatedactivity.deleted

A calendar activity was created, changed, or deleted

View details →
registration.createdregistration.waitlistedregistration.deleted

A registration was created, waitlisted, or deleted

View details →
thread.created

A new message thread was opened

View details →
message.createdmessage.updatedmessage.deleted

A message was posted, edited, or deleted

View details →
announcement.sent

An announcement was sent to residents or connections

View details →
newsletter.sent

A newsletter was sent

View details →
photo.uploadedphoto.updatedphoto.deleted

A photo was uploaded, updated, or deleted

View details →
notification.activity_cancellationnotification.registration_remindernotification.new_messagenotification.new_announcementnotification.newsletter_publishednotification.transportation_remindernotification.transportation_creator_updatenotification.transportation_commentnotification.work_request_creator_updatenotification.work_request_comment

A user-facing notification was triggered (reminders, new messages, cancellations)

View details →
Planned
transportation_request.createdtransportation_request.updatedtransportation_request.deletedtransportation_request.comment_created

A transportation request was created, updated, deleted, or commented on

View details →
Planned
work_request.createdwork_request.updatedwork_request.deletedwork_request.comment_created

A work request was created, updated, deleted, or commented on

View details →
Event envelopewebhook.json
{
  "eventId": "f3a91bc2-4d12-4e88-a1c3-8f2901dd7c94",
  "eventType": "resident.created",
  "aggregateType": "resident",
  "tenant": "sunrise-001",
  "occurredAt": "2026-06-18T10:30:00Z",
  "resourceId": "res-001"
}
Handle a delivery
// Express handler
app.post('/lifeloop/webhook', express.json(), (req, res) => {
  const key = req.get('X-API-KEY');
  if (key !== process.env.LIFELOOP_WEBHOOK_KEY) {
    return res.sendStatus(401);
  }
  if (alreadyProcessed(req.body.eventId)) return res.sendStatus(200);
  queue.push(req.body); // re-read the resource asynchronously
  res.sendStatus(200);   // acknowledge fast (any 2xx)
});