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 #

ParameterTypeRequiredDescription
leadIdnumberYesThe positive integer ID of the lead to move.
pipelineSlugstringYesThe unique API slug of the pipeline (e.g. "default_pipeline").
stageSlugstringYesThe 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 MessageCauseResolution
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 / stageSlugAn empty string or non-string value was passed.Ensure slugs are valid non-empty strings.