Skip to main content
Webhooks deliver real-time HTTP POST notifications to your endpoint when data changes in a Lofty account. Instead of polling the API, register an HTTPS callback URL and Lofty pushes a JSON payload on each subscribed event.

Subscribe

The callbackUrl must use HTTPS. HTTP endpoints are rejected.

Manage subscriptions

Delivery timing

Events to a healthy endpoint are typically delivered within 1 minute of the triggering change. Actual delivery speed depends on your endpoint. Lofty delivers to each endpoint over a limited number of concurrent connections, so a slow handler queues its own events: an endpoint that responds in under a second keeps up with any volume, while one that takes several seconds per request can fall minutes behind at peak — see the throughput note under Best practices. Failed deliveries follow the retry schedule below. Deliveries to a disabled subscription pause and resume automatically after recovery — see Health probes.

Retries and failure handling

A delivery counts as successful when your endpoint returns any 2xx status code. Any other response — an error status, a timeout, or a connection failure — is handled by the rules in this section.

Retry schedule

Failed deliveries are retried up to 9 total attempts within 48 hours, with exponential backoff between attempts: Each delay includes ±20% random jitter so retries from many events don’t arrive in synchronized bursts. An event that still cannot be delivered 48 hours after it was created is discarded.

Response handling

Idempotent delivery

Every delivery request carries a Lofty-Webhook-Id header. Its value is unique per event and stable across retries. If a timeout caused your response to be lost, the retry arrives with the same Lofty-Webhook-Id — use it to deduplicate instead of processing the event twice.

Endpoint health and automatic disabling

Lofty tracks delivery health per subscription and disables a subscription automatically when:
  • your endpoint returns 410 Gone — immediately, or
  • deliveries fail continuously with no successes in between — within hours for high-volume endpoints, or after roughly a day of sustained failures otherwise.
While a subscription is disabled, Lofty stops attempting deliveries to it. Pending events wait for recovery but still expire 48 hours after creation.

Health probes and automatic recovery

Disabled subscriptions receive a ping probe approximately every 6 hours:
The first probe that gets a 2xx response re-enables the subscription, and all pending unexpired events are delivered immediately. No manual action is needed on either side.
Your receiver must return 2xx to ping probes. If your endpoint rejects unrecognized event types with an error status, a disabled subscription can never recover automatically. Acknowledge first, then ignore event types you don’t handle.

Notification recipients

Which subscribed users receive a callback depends on the subscription’s delivery mode (permissionMode). In both modes, only users in the lead’s team who have subscribed to the event type are considered.

Assignment-based delivery — permissionMode: 0 (default)

A subscriber receives the callback only for leads assigned to them or that they administer:
  • Hidden leads — only the assigned agent receives the notification.
  • Other leads — the subscriber receives it if they are the assigned agent, or a Company Owner / Company Admin. All other subscribers are excluded.

Ownership-based delivery — permissionMode: 1

A subscriber receives the callback for any lead they manage, regardless of who it is assigned to:
  • Every assignment-based case above still applies (assigned agent, Company Owner / Company Admin).
  • In addition, the subscriber receives the callback for any lead within their ownership scope — owned by their team or office, or personally owned by them — even if it is assigned to someone else.
  • Hidden leads are still delivered only to users who manage them.
Ownership-based mode is intended for team/account-level integrations that need to cover every lead in their scope, not only assigned leads. Set permissionMode when creating the subscription; it defaults to 0, so existing subscriptions are unaffected.

Common fields

All payloads include:

Event types

Call, Email, and Text webhooks do not fire for AUTO communications. Only agent-initiated (MANUAL) and after-the-fact logged (LOGGED) events trigger webhooks. Automated messages sent by Lofty (drip campaigns, auto-responders, Smart Plans, etc.) are excluded. If your integration depends on tracking all communications, you must also poll the Communication API for AUTO type events.

Event payloads

1. Agent Info

Triggered when an agent is created or updated.

2. Lead Info

Triggered when a lead is created, updated, or deleted. Only the relevant action fields are present.

3. Lead Activity

Triggered when a lead performs site activity (SiteBrowse, SiteFavorite, SiteSearch, etc.).

4. Listing Alert

Triggered when a listing alert changes.

5. Transaction

Triggered when a transaction is created, updated, or deleted. Only the relevant action fields are present.

6. Call

Triggered on a call event.

7. Email

Triggered on an email event.

8. Text

Triggered on a text/SMS event.
communicationType valuesMANUAL: agent-initiated communication. LOGGED: communication recorded after the fact. AUTO events are excluded from webhooks.

9. Note

Triggered when a note is created, updated, or deleted. Only the relevant action fields are present.

10. Task

Triggered when a task is created, updated, finished, or deleted. Multiple action fields may appear in a single payload.

11. Appointment

Triggered when an appointment is created, updated, finished, or deleted. Multiple action fields may appear in a single payload.

12. Pipeline Change

Triggered when a lead’s pipeline stage changes.

Best practices

Respond immediately. Return a 2xx before processing and move your logic to a background job. Lofty limits concurrent deliveries per endpoint, so a slow handler directly reduces your delivery throughput — at high event volume, synchronous processing is the most common cause of delayed webhooks. Handle duplicates. The same event may be delivered more than once (for example, when a timeout swallowed your response). Deduplicate with the Lofty-Webhook-Id header — it is stable across retries of the same event. Don’t assume ordering. Retries mean an older event can arrive after a newer one. Order by the updateTime field inside the payload, not by arrival time. Acknowledge pings. Return 2xx to {"eventType": "ping"} probes — they are how a disabled subscription recovers automatically. Decommission cleanly. When you shut an endpoint down for good, return 410 Gone so Lofty stops delivering immediately instead of retrying against a dead URL. Validate payloads. Check that listId matches your expected event type before processing. Use HTTPS. Plain HTTP endpoints are rejected.
Use ngrok during development to tunnel webhooks to your local machine.

Example receiver

Resolving communication events to full records

After receiving a Call / Email / Text webhook, fetch the full record by passing the event’s timelineId as the communicationId path parameter of the v2 by-ID endpoint: timelineId is the recommended round-trip key — it always points to the same lead_timeline row regardless of whether the event is MANUAL or LOGGED. The legacy callId / emailId / textId fields still ship for backward compatibility, but their underlying record changes between the two communicationType values, so they are not safe to pass to the v2 by-ID endpoints.
All IDs in webhook payloads are 64-bit integers. JavaScript clients must handle them carefully — see JS / TS Integration.