Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.lofty.com/llms.txt

Use this file to discover all available pages before exploring further.

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

POST https://api.lofty.com/v1.0/webhook
{
  "listId": 2,
  "callbackUrl": "https://your-app.example.com/webhooks/lofty",
  "limit": 100
}
FieldTypeRequiredDescription
listIdintegerYesEvent type (1–12, see table below)
callbackUrlstringYesHTTPS endpoint to receive payloads
limitintegerNoMax events per batch (default 100, max 5000)
The callbackUrl must use HTTPS. HTTP endpoints are rejected.

Manage subscriptions

MethodEndpointDescription
POST/v1.0/webhookCreate a subscription
GET/v1.0/webhooksList active subscriptions
DELETE/v1.0/webhook/{subscribeId}Delete a subscription

Delivery timing

Events are typically delivered within 1 minute. During high traffic, delivery may be delayed but will always occur within 5 minutes.

Notification recipients

  1. Lofty checks which users in the lead’s team have subscribed to the event type.
  2. Hidden leads — only the assigned agent receives the notification.
  3. Other leads — the assigned agent and Company Owner/Admin receive the notification. All other subscribers are excluded.

Common fields

All payloads include:
FieldTypeDescription
teamIdintegerTeam ID where the event occurred
listIdintegerEvent type ID (1–12)

Event types

listIdEventTriggers
1Agent InfoAgent created or updated
2Lead InfoLead created, updated, or deleted
3Lead ActivityLead site activity (browse, favorite, search)
4Listing AlertListing alert changed
5TransactionTransaction created, updated, or deleted
6CallCall event (MANUAL and LOGGED only, excludes AUTO)
7EmailEmail event (MANUAL and LOGGED only, excludes AUTO)
8TextText message event (MANUAL and LOGGED only, excludes AUTO)
9NoteNote created, updated, or deleted
10TaskTask created, updated, finished, or deleted
11AppointmentAppointment created, updated, finished, or deleted
12Pipeline ChangeLead pipeline stage changed
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.
{
  "teamId": 123456,
  "listId": 1,
  "updatedAgent": [
    {
      "agentUserId": 789,
      "updateTime": 1736935800000
    }
  ]
}
FieldTypeDescription
updatedAgentarrayList of updated agent records
updatedAgent[].agentUserIdintegerUser ID of the updated agent
updatedAgent[].updateTimeintegerEpoch milliseconds of the update

2. Lead Info

Triggered when a lead is created, updated, or deleted. Only the relevant action fields are present.
{
  "teamId": 123456,
  "listId": 2,
  "createdLead": [
    { "leadId": 456, "updateTime": 1736935800000 }
  ],
  "updatedLead": [
    { "leadId": 457, "updateTime": 1736935860000 }
  ],
  "deletedLead": [
    { "leadId": 458, "updateTime": 1736935920000 }
  ]
}
FieldTypeDescription
createdLeadarrayCreated leads (present on create)
updatedLeadarrayUpdated leads (present on update)
deletedLeadarrayDeleted leads (present on delete)
[].leadIdintegerLead ID
[].updateTimeintegerEpoch milliseconds of the change

3. Lead Activity

Triggered when a lead performs site activity (SiteBrowse, SiteFavorite, SiteSearch, etc.).
{
  "teamId": 123456,
  "listId": 3,
  "updatedLead": [
    { "leadId": 456, "updateTime": 1736935800000 }
  ]
}
FieldTypeDescription
updatedLeadarrayLeads with new activity
updatedLead[].leadIdintegerLead ID
updatedLead[].updateTimeintegerEpoch milliseconds of the activity

4. Listing Alert

Triggered when a listing alert changes.
{
  "teamId": 123456,
  "listId": 4,
  "alertId": 789
}
FieldTypeDescription
alertIdintegerID of the changed alert

5. Transaction

Triggered when a transaction is created, updated, or deleted. Only the relevant action fields are present.
{
  "teamId": 123456,
  "listId": 5,
  "createdTransaction": [
    {
      "leadId": 456,
      "transactionId": 789,
      "updateTime": 1736935800000
    }
  ],
  "updatedTransaction": [
    {
      "leadId": 457,
      "transactionId": 790,
      "updateTime": 1736935860000,
      "updatedField": { "fieldName": "newValue" },
      "updatedFields": [{ "fieldName": "newValue" }]
    }
  ],
  "deletedTransaction": [
    {
      "leadId": 458,
      "transactionId": 791,
      "updateTime": 1736935920000
    }
  ]
}
FieldTypeDescription
createdTransactionarrayCreated transactions (present on create)
updatedTransactionarrayUpdated transactions (present on update)
deletedTransactionarrayDeleted transactions (present on delete)
[].leadIdintegerAssociated lead ID
[].transactionIdintegerTransaction ID
[].updateTimeintegerEpoch milliseconds of the change
[].updatedFieldobjectChanged field key-value pair (nullable)
[].updatedFieldsarrayList of changed field key-value pairs (nullable)

6. Call

Triggered on a call event.
{
  "teamId": 123456,
  "listId": 6,
  "createdCall": [
    {
      "callId": 101,
      "leadId": 456,
      "updateTime": 1736935800000,
      "agentId": 789,
      "communicationType": "MANUAL"
    }
  ]
}
FieldTypeDescription
createdCallarrayCall event records
[].callIdintegerEvent ID (MANUAL) or timeline ID (LOGGED)
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the call
[].agentIdintegerAgent user ID
[].communicationTypestringMANUAL or LOGGED

7. Email

Triggered on an email event.
{
  "teamId": 123456,
  "listId": 7,
  "createdEmail": [
    {
      "emailId": 101,
      "leadId": 456,
      "updateTime": 1736935800000,
      "agentId": 789,
      "communicationType": "MANUAL"
    }
  ]
}
FieldTypeDescription
createdEmailarrayEmail event records
[].emailIdintegerEvent ID (MANUAL) or timeline ID (LOGGED)
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the event
[].agentIdintegerAgent user ID
[].communicationTypestringMANUAL or LOGGED

8. Text

Triggered on a text/SMS event.
{
  "teamId": 123456,
  "listId": 8,
  "createdText": [
    {
      "textId": 101,
      "leadId": 456,
      "updateTime": 1736935800000,
      "agentId": 789,
      "communicationType": "MANUAL"
    }
  ]
}
FieldTypeDescription
createdTextarrayText message event records
[].textIdintegerEvent ID (MANUAL) or timeline ID (LOGGED)
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the event
[].agentIdintegerAgent user ID
[].communicationTypestringMANUAL or LOGGED
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.
{
  "teamId": 123456,
  "listId": 9,
  "createdNote": [
    {
      "noteId": 101,
      "leadId": 456,
      "updateTime": 1736935800000,
      "noteType": "Manual",
      "agentId": 789
    }
  ],
  "updatedNote": {
    "noteId": 102,
    "leadId": 457,
    "updateTime": 1736935860000,
    "noteType": "Manual",
    "agentId": 789
  },
  "deletedNote": {
    "noteId": 103,
    "leadId": 458,
    "updateTime": 1736935920000,
    "noteType": "Manual",
    "agentId": 789
  }
}
FieldTypeDescription
createdNotearrayCreated notes (present on create)
updatedNoteobjectUpdated note (present on update)
deletedNoteobjectDeleted note (present on delete)
[].noteIdintegerNote ID
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the change
[].noteTypestringManual, System, or AI
[].agentIdintegerAgent user ID

10. Task

Triggered when a task is created, updated, finished, or deleted. Multiple action fields may appear in a single payload.
{
  "teamId": 123456,
  "listId": 10,
  "createdTask": [
    { "taskId": 101, "leadId": 456, "updateTime": 1736935800000 }
  ],
  "updatedTask": [
    { "taskId": 102, "leadId": 457, "updateTime": 1736935860000 }
  ],
  "finishedTask": [
    { "taskId": 103, "leadId": 458, "updateTime": 1736935920000 }
  ],
  "deletedTask": [
    { "taskId": 104, "leadId": 459, "updateTime": 1736935980000 }
  ]
}
FieldTypeDescription
createdTaskarrayCreated tasks (present on create)
updatedTaskarrayUpdated tasks (present on update)
finishedTaskarrayFinished tasks (present on finish)
deletedTaskarrayDeleted tasks (present on delete)
[].taskIdintegerTask ID
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the change

11. Appointment

Triggered when an appointment is created, updated, finished, or deleted. Multiple action fields may appear in a single payload.
{
  "teamId": 123456,
  "listId": 11,
  "createdAppt": [
    { "apptId": 101, "leadId": 456, "updateTime": 1736935800000 }
  ],
  "updatedAppt": [
    { "apptId": 102, "leadId": 457, "updateTime": 1736935860000 }
  ],
  "finishedAppt": [
    { "apptId": 103, "leadId": 458, "updateTime": 1736935920000 }
  ],
  "deletedAppt": [
    { "apptId": 104, "leadId": 459, "updateTime": 1736935980000 }
  ]
}
FieldTypeDescription
createdApptarrayCreated appointments (present on create)
updatedApptarrayUpdated appointments (present on update)
finishedApptarrayFinished appointments (present on finish)
deletedApptarrayDeleted appointments (present on delete)
[].apptIdintegerAppointment ID
[].leadIdintegerAssociated lead ID
[].updateTimeintegerEpoch milliseconds of the change

12. Pipeline Change

Triggered when a lead’s pipeline stage changes.
{
  "teamId": 123456,
  "listId": 12,
  "updatedLeadstage": [
    {
      "leadId": 456,
      "updateTime": 1736935800000,
      "changeInfo": {
        "oldstage": "New Lead",
        "newstage": "Contacted"
      }
    }
  ]
}
FieldTypeDescription
updatedLeadstagearrayPipeline stage change records
[].leadIdintegerLead ID
[].updateTimeintegerEpoch milliseconds of the stage change
[].changeInfo.oldstagestringPrevious pipeline stage name
[].changeInfo.newstagestringNew pipeline stage name

Best practices

Respond immediately. Return 200 OK before processing. Move logic to a background job. Lofty may retry if no 200 is received. Handle duplicates. The same event may be delivered more than once. Use event IDs and timestamps for idempotency. 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

const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhooks/lofty', (req, res) => {
  res.sendStatus(200);
  const { listId, events } = req.body;
  processEvents(listId, events).catch(console.error);
});

async function processEvents(listId, events) {
  for (const event of events) {
    console.log(`Event type ${listId}:`, event);
  }
}

app.listen(3000);
All IDs in webhook payloads are 64-bit integers. JavaScript clients must handle them carefully — see JS / TS Integration.