> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendler.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# lead.updated

> Triggered when a lead's status changes

This event is triggered when a lead's status changes, whether through campaign automation or manual updates via the API.

## When This Event Fires

* Lead status is updated via the [Update Lead Status API](https://docs.sendler.ai/api-reference/endpoint/patch-lead-status.md)
* Campaign automation changes lead status
* Lead progresses through the campaign sequence

## Payload

```json theme={null}
{
  "eventId": "evt_1708456789123_abc123def",
  "eventType": "lead.updated",
  "timestamp": "2024-02-24T10:30:00.000Z",
  "workspaceId": "ws_abc123xyz",
  "data": {
    "leadId": "lead_abc123",
    "campaignId": "camp_xyz789",
    "linkedinUrl": "https://www.linkedin.com/in/john-doe",
    "previousStatus": "REPLY_RECEIVED",
    "newStatus": "OPPORTUNITY"
  }
}
```

## Payload Fields

| Field | Type | Description |
| - | - | - |
| `eventId` | string | Unique event identifier for idempotency |
| `eventType` | string | Always `lead.updated` |
| `timestamp` | string | ISO 8601 timestamp when the status changed |
| `workspaceId` | string | Your workspace ID |
| `data.leadId` | string | The lead whose status changed |
| `data.campaignId` | string | The campaign this lead belongs to |
| `data.linkedinUrl` | string | LinkedIn profile URL of the lead |
| `data.previousStatus` | string | Status before the change |
| `data.newStatus` | string | New status after the change |

## Campaign Status Values

| Status | Description |
| - | - |
| `PENDING` | Lead added but no action taken yet |
| `PROCESSING` | Lead is being processed |
| `CONNECTION_SENT` | Connection request sent |
| `CONNECTION_ACCEPTED` | Connection accepted by lead |
| `MESSAGE_SENT` | Follow-up message sent |
| `REPLY_RECEIVED` | Lead has replied |
| `FOLLOWUP_SENT` | Follow-up message sent |
| `BLOCKED` | Lead blocked the sender |
| `PROFILE_UNREACHABLE` | Profile is unreachable |
| `RATE_LIMITED` | Rate limited by LinkedIn |
| `FAILED` | Action failed |
| `SUCCESS` | Campaign completed successfully |
| `UNSUBSCRIBED` | Lead unsubscribed |
| `IRRELEVANT` | Lead marked as irrelevant |
| `SKIPPED` | Lead was skipped |
| `DONE` | Lead journey completed |
| `MEETING_BOOKED` | Meeting has been booked |
| `OPPORTUNITY` | Marked as sales opportunity |
| `LIKED_POST` | Lead liked a post |

## Custom Lead Status Values

| Status | Description |
| - | - |
| `LEAD` | New lead (default) |
| `INTERESTED` | Lead has shown interest |
| `MEETING_BOOKED` | Meeting has been scheduled |
| `MEETING_COMPLETE_NOT_CLOSED` | Meeting completed but deal not closed |
| `CLOSED` | Deal closed/won |
| `WRONG_PERSON` | Wrong contact/person |
| `NOT_INTERESTED` | Lead is not interested |
| `NO_RESPONSE` | No response received |

## Use Cases

> **CRM Sync**
>
> Keep your CRM in sync with lead status changes

> **Pipeline Tracking**
>
> Track leads through your sales pipeline

> **Alerting**
>
> Alert team when leads become opportunities

> **Automation**
>
> Trigger external workflows based on status

## Example Handler

```javascript theme={null}
app.post('/webhooks/sendpilot', async (req, res) => {
  const event = req.body;
  
  if (event.eventType === 'lead.updated') {
    const { leadId, previousStatus, newStatus, linkedinUrl } = event.data;
    
    // Sync status to CRM
    await crm.updateLead(leadId, {
      status: mapToCustomStatus(newStatus),
      lastStatusChange: event.timestamp
    });
    
    // Alert on high-value transitions
    if (newStatus === 'OPPORTUNITY') {
      await slack.postMessage({
        channel: '#sales-opportunities',
        text: `🎯 New opportunity!\n` +
              `Lead: ${linkedinUrl}\n` +
              `Previous status: ${previousStatus}`
      });
    }
    
    // Handle negative outcomes
    if (newStatus === 'NOT_INTERESTED') {
      await analytics.track('lead_lost', {
        leadId,
        previousStatus
      });
    }
    
    console.log(`Lead ${leadId}: ${previousStatus} → ${newStatus}`);
  }
  
  res.status(200).send('OK');
});

function mapToCustomStatus(sendpilotStatus) {
  const mapping = {
    'PENDING': 'new',
    'CONNECTION_SENT': 'contacted',
    'CONNECTION_ACCEPTED': 'connected',
    'MESSAGE_SENT': 'in_conversation',
    'REPLY_RECEIVED': 'engaged',
    'OPPORTUNITY': 'qualified',
    'NOT_INTERESTED': 'closed_lost',
    'DONE': 'closed_won'
  };
  return mapping[sendpilotStatus] || 'unknown';
}
```

> [!NOTE]
>
> Status changes can be frequent as leads progress through campaign sequences. Consider batching or debouncing if you're making external API calls on each status change.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.