> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpilot.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](/api-reference/endpoint/patch-lead-status)
* 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

<CardGroup cols={2}>
  <Card title="CRM Sync" icon="database">
    Keep your CRM in sync with lead status changes
  </Card>

  <Card title="Pipeline Tracking" icon="chart-line">
    Track leads through your sales pipeline
  </Card>

  <Card title="Alerting" icon="bell">
    Alert team when leads become opportunities
  </Card>

  <Card title="Automation" icon="gears">
    Trigger external workflows based on status
  </Card>
</CardGroup>

## 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.
</Note>
