> ## Documentation Index
> Fetch the complete documentation index at: https://developer.fitprotracker.com/llms.txt
> Use this file to discover all available pages before exploring further.

# contact.status_changed

> A contact moved between lifecycle groups (Lead → Member → etc.).

A `contact.status_changed` event fires when a contact's **Contact Group** (lifecycle stage) changes. Contact Groups in FPT are the canonical lifecycle enum:

| ID | Group        | Meaning                                          |
| -- | ------------ | ------------------------------------------------ |
| 1  | Leads        | Prospective customers — not yet engaged          |
| 2  | Prospects    | Active interest, possibly in trial               |
| 3  | Members      | Paying customers with active memberships         |
| 4  | Past Members | Former customers, churned                        |
| 5  | Non-members  | Active in the system but not on a membership     |
| 6  | Other        | Catch-all for non-standard cases                 |
| 7  | Staff        | Employees / trainers (separate from gym members) |

When a contact transitions between these — like a lead converting to a member, or a member churning to past-member — this event fires with both the previous and new group IDs.

## Payload

```json theme={null}
{
  "eventId":        "9f1c7e2a8c4d4b1b9e3f5a6d7c8b9a0e",
  "eventType":     "contact.status_changed",
  "eventTimestamp": "2026-06-10T23:45:00.123Z",
  "locationId":    1234,
  "organizationId": 5678,
  "apiVersion":    "2026-05-29",
  "data": {
    "contactId":          9876,
    "firstName":          "Jane",
    "lastName":           "Doe",
    "fullName":           "Jane Doe",
    "email":              "jane@example.com",
    "phone":              "+15551234567",
    "isActive":           true,
    "contactGroupId":     3,
    "subGroupId":         null,
    "subGroupName":       null,
    "previousStatusId":   1,
    "newStatusId":        3,
    "previousStatusName": "Leads",
    "newStatusName":      "Members"
  }
}
```

### Fields in `data`

The payload carries the **identity baseline** (same shape as [`contact.created`](/events/contact-created)) plus the diff fields specific to this event. You can act on a status change without maintaining your own `contactId → identity` lookup — the contact's name, email, and phone are right there in the payload.

| Field                               | Type               | Description                                                       |
| ----------------------------------- | ------------------ | ----------------------------------------------------------------- |
| `contactId`                         | `number`           | The contact whose status changed.                                 |
| `firstName`, `lastName`, `fullName` | `string`           | Identity at the time of the change.                               |
| `email`, `phone`                    | `string`           | Direct contact channels — usable immediately for outreach.        |
| `isActive`                          | `boolean`          | `true` for a live contact.                                        |
| `contactGroupId`                    | `number`           | Current Contact Group ID (same as `newStatusId`).                 |
| `subGroupId`                        | `number` or `null` | Current sub-group ID (location-scoped).                           |
| `subGroupName`                      | `string` or `null` | Current sub-group label.                                          |
| `previousStatusId`                  | `number`           | The Contact Group ID BEFORE the change.                           |
| `newStatusId`                       | `number`           | The Contact Group ID AFTER the change (same as `contactGroupId`). |
| `previousStatusName`                | `string`           | Label for `previousStatusId` (e.g., `"Leads"`, `"Past Members"`). |
| `newStatusName`                     | `string`           | Label for `newStatusId`.                                          |

<Note>
  **Why "status" instead of "contact group"?** Externally, "status" is the more universal term for a lifecycle stage. Internally FPT calls it Contact Group. The event name uses the partner-facing label; the table above documents the mapping.
</Note>

## What triggers it

* Staff explicitly changes a contact's group in the admin
* An automation triggers a group change (e.g., "When trial ends → flip to Past Member")
* Billing lifecycle (e.g., "Member's last payment failed and they churned → flip to Past Member") — when the billing-driven flow eventually publishes its own events (v1.2), you may receive a `payment.failed` or `membership.cancelled` shortly before this
* A contact-import flow assigns groups in bulk

## Important: multiple rapid transitions get coalesced

If a contact's status changes Lead → Prospect → Member in 200ms (rare but possible via automation chains), the `previousStatusId` you receive may be Lead and `newStatusId` may be Member — skipping Prospect entirely. The intermediate state isn't lost in FPT's database; it just doesn't surface as a separate event.

If you need to track every step, use FPT's contact-history API (when released) rather than relying on this event being granular.

## What you might do with this

* **Trigger a marketing automation** in your platform when leads convert to members
* **Update analytics dashboards** for conversion rate, churn rate, lifecycle funnel
* **Sales notifications** — "your assigned lead just became a member"
* **Workflow rules** — "if a Member becomes a Past Member, ask for feedback via survey"
