Onsidian Help
Lead System

State Machine

How leads move through stages and statuses

Every lead has two fields that control its lifecycle: status and stage. Status is the high-level bucket (open or resolved). Stage is the specific workflow position within that status.

Statuses

StatusMeaning
openLead is active and being worked
resolvedLead has reached a terminal outcome

Stages

Open stages

These represent where the lead is in the contact-to-appointment workflow.

StageMeaningHow a lead gets here
newJust created, no contact attempt yetInitial state on creation
attemptedAgent has tried to contactFirst contact_attempted activity
callbackLead requested a callbackcallback_requested activity, or appointment cancelled
scheduledAppointment is bookedappointment_scheduled activity
no_showLead didn't show for appointmentappointment_no_show activity

Resolved stages (terminal outcomes)

These end the lead's lifecycle. Once resolved, no further stage transitions occur.

StageMeaningConstraints
saleLead purchasedOnly from scheduled stage
no_salePresentation given, no purchaseOnly from scheduled stage
refusedLead explicitly refusedAny open stage
wrong_numberPhone number belongs to someone elseAny open stage
bad_numberPhone number disconnected/invalidAny open stage
unresponsiveLead stopped respondingCannot be applied from new (must have been contacted first)
duplicateDuplicate of another leadAny open stage
dncDo Not Contact — lead requested no further contactAny open stage

Transition diagram

         new

          │ contact_attempted

       attempted

          ├─── callback_requested ──► callback
          │                              │
          │                              │ appointment_scheduled
          │                              ▼
          ├─── appointment_scheduled ──► scheduled ◄── appointment_scheduled ── no_show
          │                              │    │                                    ▲
          │                              │    │ appointment_no_show                │
          │                              │    └────────────────────────────────────┘
          │                              │
          │                              │ appointment_cancel
          │                              └──► callback

          │   (from any open stage)
          ├──► refused     [resolved]
          ├──► wrong_number [resolved]
          ├──► bad_number   [resolved]
          ├──► duplicate    [resolved]
          ├──► dnc          [resolved]

          │   (from any except 'new')
          └──► unresponsive [resolved]

     sale ◄── (only from scheduled) [resolved]
   no_sale ◄── (only from scheduled) [resolved]

How transitions happen

Transitions are not managed by the UI. They happen automatically in the database via the update_lead_status_based_on_activity trigger function, which fires on every lead_activity INSERT.

The trigger:

  1. Reads the new activity's type
  2. Looks up the lead's current stage and status
  3. If status = 'resolved', exits early (no further transitions)
  4. Applies the transition rules and updates leads.stage and leads.status

This means the UI only needs to log the correct activity type — it never directly writes to stage or status.

Terminal outcome rules

The trigger enforces two constraints on terminal outcomes:

  1. sale and no_sale can only be applied when stage = 'scheduled'. The presentation flow enforces this — you can't start a presentation without an appointment.

  2. unresponsive cannot be applied when stage = 'new'. A lead must have been contacted at least once before being marked unresponsive.

All other terminal outcomes (refused, wrong_number, bad_number, duplicate, dnc) can be applied from any open stage.

Re-opening leads

There is currently no mechanism to re-open a resolved lead. Once resolved, the lead stays resolved. If needed, a new lead can be created manually.

On this page