crm.leads.changeStage
#
Transitions a lead to a new pipeline stage using the target pipeline slug and stage slug. Moving a stage automatically triggers all configured ON_EXIT actions for the departing stage and ON_ENTER actions for the destination stage.
TypeScript Signature #
typescript
crm.leads.changeStage(
leadId: number,
pipelineSlug: string,
stageSlug: string
): Promise<Lead>;
Parameters Reference #
| Parameter | Type | Required | Description |
|---|---|---|---|
leadId | number | Yes | The positive integer ID of the lead to move. |
pipelineSlug | string | Yes | The unique API slug of the pipeline (e.g. "default_pipeline"). |
stageSlug | string | Yes | The unique API slug of the stage (e.g. "proposal_sent", "closed_won"). |
Returns: Promise<Lead> updated with the new stageId and timestamped stageUpdatedAt.
âšī¸
Note
Stage transitions automatically generate timeline activity records (ActivityEntityType.LEAD) and stage history logs (LeadStageHistory) recording the prior stage name, new stage name, and actor identity.
Minimal Quickstart Example #
typescript
async function run(context: Context, dolfin: DolfinApi): Promise<void> {
const { lead } = context;
const crm = await dolfin.crm.module(lead.moduleId);
// Transition to "qualified" stage
await crm.leads.changeStage(lead.id, "default_pipeline", "qualified");
}
Production Recipe: Automated Stage Progression Rotator #
This recipe inspects the module's stage hierarchy, calculates the next chronological stage index, advances the lead, and records diagnostic notes.
typescript
async function run(context: Context, dolfin: DolfinApi): Promise<void> {
const { lead } = context;
const crm = await dolfin.crm.module(lead.moduleId);
console.log(`Evaluating progression for lead "${lead.name}" (ID: ${lead.id})`);
try {
// 1. Fetch ordered list of stages for this module
const stages = await crm.stages.list();
const currentIndex = stages.findIndex((s) => s.id === lead.stageId);
if (currentIndex === -1) {
console.warn(`Current stage ID ${lead.stageId} not found in pipeline stages.`);
return;
}
// 2. Check if already at final stage
if (currentIndex >= stages.length - 1) {
console.log(`Lead #${lead.id} is already in final stage (${stages[currentIndex].name}).`);
return;
}
// 3. Select next stage
const nextStage = stages[currentIndex + 1];
console.log(`Advancing lead from stage "${stages[currentIndex].name}" to "${nextStage.name}"`);
// 4. Execute stage transition
await crm.leads.changeStage(lead.id, "default_pipeline", nextStage.slug);
// 5. Append timeline note
await crm.leads.notes.add(
lead.id,
`đ Automated advancement: Moved from "${stages[currentIndex].name}" to "${nextStage.name}".`
);
console.log(`Successfully advanced lead #${lead.id} to "${nextStage.name}" (${nextStage.slug}).`);
} catch (error: any) {
console.error(`Stage transition failed: ${error.message}`);
throw error;
}
}
Common Errors & Troubleshooting #
| Error Message | Cause | Resolution |
|---|---|---|
Pipeline with slug "..." not found in this module. | The pipeline slug does not match any pipeline configured in this module. | Verify pipeline slug using crm.pipelines.list(). |
Stage with slug "..." not found in pipeline "...". | The stage slug does not exist within the specified pipeline. | Verify stage slug using crm.stages.list(). |
Invalid pipelineSlug / stageSlug | An empty string or non-string value was passed. | Ensure slugs are valid non-empty strings. |