MSP Contact Lifecycle
Last updated: 2026-06-11.
This page documents the implemented CRM Contact automations that keep MSP Seats aligned with onboarding, recurring, and offboarding contact states.
Contact Created
When a Contact is created, the automation tries to create or reuse an MSP Seat for the Contact if the Contact belongs to a company with exactly one active Managed Services Plan.
Rules currently implemented:
- If the Contact has no company, no seat is created.
- If the Contact came from the onboarding form and has no company, a warning email is sent to the configured debug recipients so the Contact can be fixed.
- If the company has no active MSP plan, no seat is created.
- If the company has more than one active MSP plan, the automation stops and sends a manual-review email. It does not guess which plan is correct.
- If the Contact or active MSP plan is missing an ID, the automation stops for manual review.
- If more than one MSP Seat already exists for the same Contact and Plan, the automation stops for manual review.
- If exactly one matching MSP Seat already exists, the automation reuses it
and still ensures the Contact lead status is
ONBOARDING. - If no matching MSP Seat exists, the automation creates one with:
Plan: the single active plan for the Contact company;Contact: the created Contact;Billing_Status:Onboarding;Billing_Start: the ContactCreated_Timedate;Billing_End: blank.
- Whenever the automation can safely continue past the plan/seat checks, it
ensures the Contact
Lead_StatusisONBOARDING.
Business reasoning:
- A new staff Contact for an MSP client should become billable/onboarding data only when the owning company and target plan are unambiguous.
- Onboarding starts as a seat lifecycle state, but the Contact also moves to
ONBOARDINGso existing CRM views and team workflows remain aligned. - Duplicate seats and multiple active plans are treated as data-quality issues, not as cases for automation to resolve silently.
Contact Edited
When a Contact is edited, the automation looks at update_source first, then
at Lead_Status.
Offboarding Form
If update_source is offboarding_form, the automation treats the edit as an
offboarding event.
Rules currently implemented:
- The same company / single active plan / single matching seat checks apply.
- If a corresponding MSP Seat exists, it is ended:
Billing_Status:Ended;Billing_End: today.
- If the seat is already
Endedand already has aBilling_End, the existing end date is preserved. - After the seat is ended or confirmed ended, the Contact is updated to:
Lead_Status:BUSINESS PREVIOUS;update_source: blank.
Recurring Contact Status
If Lead_Status is BUSINESS RECURRING or BUSINESS OWNER RECURRING, the
Contact should have an active MSP Seat.
Rules currently implemented:
- If no corresponding MSP Seat exists, one is created with
Billing_StatusActiveandBilling_Startset to today. - If a corresponding seat exists but is ended or onboarding, it is updated to:
Billing_Status:Active;Billing_End: blank.
- If the seat is already active with no end date, no seat change is needed.
Onboarding Contact Status
If Lead_Status is ONBOARDING, the Contact should have an onboarding MSP
Seat.
Rules currently implemented:
- If no corresponding MSP Seat exists, one is created with
Billing_StatusOnboardingandBilling_Startset to today. - If a corresponding seat exists, it is updated to
Billing_StatusOnboarding. Billing_Endis cleared when needed so the seat can participate in the current lifecycle again.
Business Previous Status
If Lead_Status is BUSINESS PREVIOUS, the Contact should stop counting as an
active MSP seat only when the current seat is active.
Rules currently implemented:
- If a corresponding seat is
Active, it is ended withBilling_StatusEndedandBilling_Endset to today. - If the corresponding seat is not active, the automation skips rather than forcing a different lifecycle transition.
- If no corresponding seat exists, the automation skips.
Other Edits
If the edit is not an offboarding form event and the Contact lead status is not one of the implemented MSP lifecycle statuses, no MSP Seat change is made.
Review and Skip Rules
The automation skips safely when:
- the Contact has no company;
- the company has no active MSP plan;
- the edit does not match an implemented MSP lifecycle case;
- a
BUSINESS PREVIOUSContact has no active corresponding seat to end.
The automation asks for manual review when:
- the company has multiple active MSP plans;
- the Contact or plan is missing an ID;
- more than one MSP Seat exists for the same Contact and Plan;
- an existing seat that must be updated has no seat ID.
Manual-review and warning emails are sent to DEBUG_RECIPIENT_EMAILS through
Zoho Mail.
Deliberate Limits
- The Deluge functions do not contain business logic; they only pass the Contact ID to middleware.
- The automation does not choose between multiple active plans.
- The automation does not merge duplicate seats.
- The automation does not create or update Managed Services Plans.
References
- Technical route:
POST /zoho/contacts/on-create - Technical route:
POST /zoho/contacts/on-edit - Code:
app/automations/contact_created.py - Code:
app/automations/contact_edited.py - Deluge wrappers:
zoho_crm/deluge/standalone.on_create_contact_automations.dg,zoho_crm/deluge/standalone.on_edit_contact_automations.dg - Tests:
tests/test_contact_created_automation.py,tests/test_contact_edited_automation.py