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
Campaign automation changes lead status
Lead progresses through the campaign sequence
Payload
{
"eventId" : "evt_1708456789123_abc123def" ,
"eventType" : "lead.status.changed" ,
"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" ,
"changedBy" : "api"
}
}
Payload Fields
Field Type Description eventIdstring Unique event identifier for idempotency eventTypestring Always lead.status.changed timestampstring ISO 8601 timestamp when the status changed workspaceIdstring Your workspace ID data.leadIdstring The lead whose status changed data.campaignIdstring The campaign this lead belongs to data.linkedinUrlstring LinkedIn profile URL of the lead data.previousStatusstring Status before the change data.newStatusstring New status after the change data.changedBystring How the change was triggered: api, automation, or user
Status Values
Status Description PENDINGLead added but no action taken yet CONNECTION_SENTConnection request sent CONNECTION_ACCEPTEDConnection accepted by lead MESSAGE_SENTFollow-up message sent REPLY_RECEIVEDLead has replied OPPORTUNITYMarked as sales opportunity NOT_INTERESTEDLead declined or not interested DONELead journey completed
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
app . post ( '/webhooks/sendpilot' , async ( req , res ) => {
const event = req . body ;
if ( event . eventType === 'lead.status.changed' ) {
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' ;
}
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.