# Events & Payloads (/docs/api-reference/webhooks/events)



These are the events careCycle can deliver. When you
[add an endpoint](/docs/api-reference/webhooks#setting-up-webhooks) you can
subscribe to all events or only the ones you care about.

| Event                            | Fires when                                                                                                                           |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `customer.created`               | A customer is created (manual entry, inbound call, lead capture, or an integration). Bulk CSV imports do not emit this event.        |
| `customer.updated`               | A customer's details are edited.                                                                                                     |
| `customer.unsubscribed`          | A customer opts out of contact: they reply STOP to a text, a carrier block is applied, or a rep marks them do-not-call / do-not-SMS. |
| `call.completed`                 | A call finishes and its details (transcript, duration, disposition) are finalized.                                                   |
| `sms.sent`                       | An outbound SMS/RCS message is sent to a customer (campaign, appointment, or a manual reply from the inbox).                         |
| `sms.received`                   | An inbound SMS/RCS message is received from a customer.                                                                              |
| `inbox.conversation_marked_done` | A rep marks an inbox conversation (thread) as done.                                                                                  |
| `inquiry.callback_scheduled`     | A rep resolves a customer inquiry by scheduling an AI callback.                                                                      |
| `policy.created`                 | A policy is added to a customer (manual entry, script, or an integration). Bulk CSV imports do not emit this event.                  |
| `policy.updated`                 | A policy's details are edited (including status changes).                                                                            |
| `appointment.scheduled`          | An appointment is booked for a customer (by the voice AI, a rep in the dashboard, or the customer via a self-serve scheduling link). |
| `appointment.confirmed`          | A customer confirms their appointment.                                                                                               |
| `appointment.rescheduled`        | An appointment is moved to a new time.                                                                                               |
| `appointment.cancelled`          | An appointment is cancelled.                                                                                                         |
| `appointment.no_show`            | A customer does not show up for their appointment.                                                                                   |
| `appointment.completed`          | An appointment takes place and is marked complete.                                                                                   |
| `appointment.member_reassigned`  | An appointment is reassigned to a different team member.                                                                             |

<Callout type="info">
  Every payload includes a top-level &#x2A;*`event_type`** field (e.g.
  `"customer.created"`); switch on it to route events. This matters most for
  `customer.created` and `customer.updated`, which are otherwise identical in
  shape. The same value is also sent as the Svix event type for endpoint-level
  subscription filtering.
</Callout>

All IDs are UUIDs, timestamps are ISO 8601, and any field with no value is
`null`. Phone numbers are E.164.

`customer.created` [#customercreated]

Sent when a new customer record is created. The payload is the full customer
object.

```json
{
  "event_type": "customer.created",
  "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "createdAt": "2026-06-17T19:07:23.709Z",
  "updatedAt": "2026-06-17T19:07:23.709Z",
  "externalId": "CRM-48213",
  "status": "Lead",
  "firstName": "Marcus",
  "middleName": null,
  "lastName": "Delacroix",
  "salutation": null,
  "suffix": null,
  "preferredName": null,
  "phoneNumber": "+13128471928",
  "isPhonePrimary": true,
  "lineType": "mobile",
  "email": "marcus.delacroix@example.com",
  "dateOfBirth": "1958-04-12",
  "language": "en",
  "ethnicity": null,
  "gender": "Male",
  "maritalStatus": "Married",
  "address": "4427 Westbrook Ave",
  "address2": "Apt 3B",
  "city": "Mesa",
  "county": "Maricopa",
  "state": "AZ",
  "postalCode": "85204",
  "timezone": "America/Phoenix",
  "mbiNumber": "1EG4TE5MK73",
  "medicareCard": true,
  "medicarePartADate": "2023-05-01",
  "medicarePartBDate": "2023-05-01",
  "hasMedicaid": false,
  "medicaidNumber": null,
  "socialSecurityDisability": false,
  "veteran": true,
  "vaNumber": null,
  "heightInches": 72,
  "weightPounds": 195,
  "smokerStatus": false,
  "householdIncome": 42000,
  "annualIncome": 42000,
  "filingStatus": "married_joint",
  "dependentCount": 0,
  "subsidyEligible": true,
  "subsidyAmount": 148,
  "carrierAssignedCustomerId": null,
  "agentName": null,
  "agentNpn": null,
  "assignedUser": {
    "id": "b396018f-7d49-4a55-abe5-544174abcaaa",
    "name": "Priya Raman",
    "email": "priya@youragency.com",
    "npn": "8419302",
    "role": "agent",
    "licensedStates": ["AZ", "AR"]
  },
  "doNotCall": false,
  "doNotSMS": false,
  "doNotEmail": false,
  "doNotMail": false,
  "testCustomer": false,
  "phonePrimaryCustomerId": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "relationships": [
    {
      "id": "4c2a9e71-0b3d-4f6a-9e8c-1d2b3a4c5e6f",
      "relatedCustomerId": "7e3d1b9a-5c4f-4a2e-8d6b-9f0a1c2e3d4b",
      "relationshipType": "spouse",
      "direction": "outgoing"
    }
  ]
}
```

Every field below is present on `customer.created` and `customer.updated`. Any
field without a value is `null`.

**Identifiers & status**

| Field                       | Type     | Description                                                                                    |
| --------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `event_type`                | string   | The webhook event: `customer.created` or `customer.updated`. Switch on this to route the event |
| `id`                        | UUID     | careCycle customer ID                                                                          |
| `createdAt` / `updatedAt`   | ISO 8601 | When the record was created / last updated                                                     |
| `externalId`                | string   | Your own identifier for the customer, if one was provided                                      |
| `status`                    | enum     | Lifecycle status: one of `Lead`, `Active`, `Inactive`                                          |
| `carrierAssignedCustomerId` | string   | The carrier's identifier for the customer, if known                                            |
| `testCustomer`              | boolean  | `true` for test records; filter these out in production                                        |

**Identity & contact**

| Field                                     | Type   | Description                                                                                                                                                      |
| ----------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firstName` / `middleName` / `lastName`   | string | Legal name parts                                                                                                                                                 |
| `salutation` / `suffix` / `preferredName` | string | Optional name extras                                                                                                                                             |
| `phoneNumber`                             | string | Primary phone number (E.164)                                                                                                                                     |
| `lineType`                                | enum   | Carrier line type: `landline`, `mobile`, `fixedVoip`, `nonFixedVoip`, `personal`, `tollFree`, `premium`, `sharedCost`, `uan`, `voicemail`, `pager`, or `unknown` |
| `email`                                   | string | Email address                                                                                                                                                    |
| `dateOfBirth`                             | date   | `YYYY-MM-DD` (a date, not a timestamp)                                                                                                                           |
| `language`                                | string | ISO 639-1 language code (e.g. `en`, `es`)                                                                                                                        |
| `ethnicity`                               | string | Free-text ethnicity, if collected                                                                                                                                |
| `gender`                                  | enum   | `Male`, `Female`, `Non-Binary`, `Other`, or `Prefer Not to Say`                                                                                                  |
| `maritalStatus`                           | enum   | `Single`, `Married`, `Divorced`, `Widowed`, `Separated`, or `Domestic Partnership`                                                                               |

**Underwriting**

Carriers use these to set a rate class on life and final expense applications.

| Field          | Type    | Description                                                                                       |
| -------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `heightInches` | integer | Total height in inches, so 6'0" is `72`                                                           |
| `weightPounds` | integer | Weight in pounds                                                                                  |
| `smokerStatus` | boolean | `null` when unknown. `false` means confirmed non-smoker, which is a different answer from unknown |

<Callout type="info">
  Social Security numbers are never included in any webhook payload, even when one
  is on file. Reading a full SSN requires a permissioned, audited API call.
</Callout>

**Address**

| Field                                      | Type   | Description                                              |
| ------------------------------------------ | ------ | -------------------------------------------------------- |
| `address` / `address2`                     | string | Street address lines                                     |
| `city` / `county` / `state` / `postalCode` | string | Locality fields; `state` is the 2-letter US abbreviation |
| `timezone`                                 | string | IANA timezone (e.g. `America/Phoenix`)                   |

**Medicare & Medicaid**

| Field                                     | Type    | Description                                  |
| ----------------------------------------- | ------- | -------------------------------------------- |
| `mbiNumber`                               | string  | Medicare Beneficiary Identifier              |
| `medicareCard`                            | boolean | Whether the customer has their Medicare card |
| `medicarePartADate` / `medicarePartBDate` | date    | `YYYY-MM-DD` Part A / Part B effective dates |
| `hasMedicaid`                             | boolean | Whether the customer has Medicaid            |
| `medicaidNumber`                          | string  | Medicaid ID, if applicable                   |
| `socialSecurityDisability`                | boolean | Receiving SSDI                               |
| `veteran`                                 | boolean | Veteran status                               |
| `vaNumber`                                | string  | VA identifier, if applicable                 |

**Financial & subsidy**

| Field                              | Type    | Description                                                             |
| ---------------------------------- | ------- | ----------------------------------------------------------------------- |
| `householdIncome` / `annualIncome` | integer | Whole US dollars (no cents)                                             |
| `filingStatus`                     | string  | Tax filing status (e.g. `single`, `married_joint`, `head_of_household`) |
| `dependentCount`                   | integer | Number of dependents                                                    |
| `subsidyEligible`                  | boolean | Eligible for a premium subsidy                                          |
| `subsidyAmount`                    | integer | Estimated monthly subsidy in whole US dollars                           |

**Assignment**

| Field                    | Type   | Description                                                                                                                                                                    |
| ------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `agentName` / `agentNpn` | string | Externally-supplied agent name and NPN, if provided                                                                                                                            |
| `assignedUser`           | object | The careCycle member assigned to the customer, or `null` if unassigned. Contains `id`, `name`, `email`, `npn`, `role`, and `licensedStates` (array of 2-letter US state codes) |

**Consent flags**

| Field                                                 | Type    | Description                                                        |
| ----------------------------------------------------- | ------- | ------------------------------------------------------------------ |
| `doNotCall` / `doNotSMS` / `doNotEmail` / `doNotMail` | boolean | Per-channel contact suppression; respect these before reaching out |

**Shared phone numbers**

A phone number can belong to more than one customer, for example a married
couple. One of them is the number's primary: inbound calls, texts and outreach
go to them. Match customers on `id` or `externalId`, never on `phoneNumber`.

| Field                    | Type    | Description                                                                                                                                                                                                                                                                                             |
| ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isPhonePrimary`         | boolean | `true` when this customer is the primary for `phoneNumber`                                                                                                                                                                                                                                              |
| `phonePrimaryCustomerId` | UUID    | The customer who is the primary for `phoneNumber` (this customer's `id` when `isPhonePrimary` is `true`)                                                                                                                                                                                                |
| `relationships`          | array   | Customers linked to this one. Each item has `id`, `relatedCustomerId`, `relationshipType` (`spouse`, `child`, `parent`, `sibling`, `power_of_attorney`, `other`) and `direction`: `outgoing` means the related customer is this customer's `relationshipType`, `incoming` means this customer is theirs |

`customer.updated` [#customerupdated]

Sent when a customer is edited. The payload is identical in shape to
[`customer.created`](#customercreated) and reflects the customer's state after
the update. `updatedAt` changes on every update. It is also sent to both
customers when a relationship is added, changed or removed, and when a phone
number's primary changes.

```json
{
  "event_type": "customer.updated",
  "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "updatedAt": "2026-06-18T14:22:09.120Z",
  "status": "Active",
  "phoneNumber": "+13128471928",
  "firstName": "Marcus",
  "lastName": "Delacroix",
  "...": "all other customer fields, same shape as customer.created"
}
```

`customer.unsubscribed` [#customerunsubscribed]

Sent when a customer is newly opted out of contact on one or more channels. This
fires on the transition into a suppressed state, whether the customer replies
STOP to a text, the carrier applies a block, or a rep marks them do-not-call /
do-not-SMS in the dashboard. Because a do-not-SMS opt-out also suppresses calls,
a single STOP typically reports both `call` and `sms` in `channels`.

`channels` lists only the channels that flipped to suppressed on this event.
`source` is one of `inbound_message`, `carrier_block`, or `manual`. The embedded
`customer` (same object as [`customer.created`](#customercreated)) reflects the
resulting `doNotCall` / `doNotSMS` / `doNotEmail` / `doNotMail` flags.

```json
{
  "event_type": "customer.unsubscribed",
  "customerId": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "unsubscribedAt": "2026-07-13T18:04:51.220Z",
  "source": "inbound_message",
  "channels": ["call", "sms"],
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "doNotCall": true,
    "doNotSMS": true,
    "...": "full customer object, same shape as customer.created"
  }
}
```

`call.completed` [#callcompleted]

Sent once a call has finished and its details are finalized. The payload
includes the call outcome, the full transcript and summary, the `campaign` it
belonged to, the human agent who handled it (`handledBy`), and the associated
`customer` (the same object as [`customer.created`](#customercreated)).

```json
{
  "event_type": "call.completed",
  "id": "dca4a483-af54-4899-a804-766ee5812537",
  "createdAt": "2026-06-17T19:07:23.709Z",
  "phoneNumber": "+13128471928",
  "callSid": "f2a91c0b-7d2e-4c8a-9f31-6b5d0a4e1c77",
  "direction": "inbound",
  "disposition": "Enrolled",
  "durationMs": 247000,
  "startTime": "2026-06-17T19:03:16.001Z",
  "endTime": "2026-06-17T19:07:23.001Z",
  "endedReason": "completed",
  "summary": "Caller confirmed eligibility and enrolled in a Medicare Advantage plan effective July 1.",
  "transcript": "Agent: Thanks for calling careCycle...\nCaller: Hi, I'd like to review my options...",
  "campaign": {
    "id": "4f952597-5c04-4d2c-851e-30f518e2c761",
    "name": "MA Inbound Receptionist",
    "slug": null,
    "description": null,
    "status": "active",
    "vertical": "medicare",
    "direction": "inbound",
    "kind": "voice_ai",
    "tags": [],
    "startDate": "2026-03-06T00:11:35.256Z",
    "endDate": null
  },
  "handledBy": {
    "id": "7c3e9f10-2b4a-4d6e-8c15-9a0b3d5e7f21",
    "name": "Dana Whitfield",
    "email": "dana.whitfield@example.com",
    "npn": "18473920"
  },
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

| Field         | Description                                                                                                                                                    |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_type`  | The webhook event: always `call.completed`                                                                                                                     |
| `id`          | careCycle call ID                                                                                                                                              |
| `phoneNumber` | The customer's phone number (E.164)                                                                                                                            |
| `direction`   | `inbound` or `outbound`                                                                                                                                        |
| `disposition` | Final outcome of the call                                                                                                                                      |
| `durationMs`  | Call duration in milliseconds                                                                                                                                  |
| `endedReason` | Why the call ended (e.g. `completed`, `no-answer`)                                                                                                             |
| `summary`     | AI-generated summary of the call                                                                                                                               |
| `transcript`  | Full call transcript                                                                                                                                           |
| `campaign`    | The campaign the call belonged to (`null` if none)                                                                                                             |
| `handledBy`   | The human agent who handled the call, or `null` when no person was on it. `id` is the agent's user ID, the same value the calls API accepts in `agentUserIds`. |
| `customer`    | The associated customer (`null` if the call wasn't linked to one)                                                                                              |

<Callout type="info">
  `call.completed` fires for every terminal call, including `no-answer`, `busy`,
  and `failed`. Use `disposition` and `endedReason` to distinguish outcomes.
</Callout>

<Callout type="warn">
  `handledBy` is the agent who was actually on this call. Do not confuse it with
  `customer.agentName` / `customer.assignedUser`, which are the customer's
  assigned agent of record and are populated regardless of who took the call (or
  whether a person took it at all). `handledBy` is `null` on AI-handled calls,
  which is the majority of call volume on most accounts.
</Callout>

`sms.sent` [#smssent]

Sent when an outbound SMS or RCS message is delivered to a customer, whether
from a campaign, an appointment workflow, or a manual reply in the inbox. The
payload carries the message fields plus the associated `customer` (the same
object as [`customer.created`](#customercreated)).

```json
{
  "event_type": "sms.sent",
  "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  "createdAt": "2026-06-25T16:48:02.114Z",
  "direction": "outbound",
  "fromNumber": "+18005551234",
  "toNumber": "+13128471928",
  "content": "Hi Marcus, just confirming your appointment tomorrow at 2pm.",
  "smsType": "appointment_reminder",
  "channel": "telnyx_sms",
  "campaignId": "4f952597-5c04-4d2c-851e-30f518e2c761",
  "sentAt": "2026-06-25T16:48:02.000Z",
  "sentBy": null,
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

`sentBy` is `null` for automated sends (campaigns, appointment workflows, bots).
When a rep sends a message manually from the inbox, it identifies that team
member:

```json
{
  "sentBy": {
    "id": "7c9e1a2b-3d4e-4f50-8a61-9b0c1d2e3f40",
    "name": "Jordan Smith",
    "email": "jordan@youragency.com",
    "npn": "1234567",
    "role": "agent",
    "licensedStates": ["IL", "IN"]
  }
}
```

`sms.received` [#smsreceived]

Sent when an inbound SMS or RCS message is received from a customer. Identical
in shape to [`sms.sent`](#smssent) with `direction` set to `inbound`. `customer`
is `null` when the inbound number can't be matched to a known customer.

```json
{
  "event_type": "sms.received",
  "id": "a2b3c4d5-6e70-4f81-9a02-1b3c4d5e6f70",
  "createdAt": "2026-06-25T16:50:31.882Z",
  "direction": "inbound",
  "fromNumber": "+13128471928",
  "toNumber": "+18005551234",
  "content": "Yes, that works. See you then!",
  "smsType": "inbound_sms",
  "channel": "telnyx_sms",
  "campaignId": null,
  "sentAt": "2026-06-25T16:50:31.000Z",
  "sentBy": null,
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

| Field                     | Type     | Description                                                                                                                                                         |
| ------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_type`              | string   | `sms.sent` or `sms.received`                                                                                                                                        |
| `id`                      | UUID     | careCycle SMS record ID                                                                                                                                             |
| `createdAt`               | ISO 8601 | When the record was created                                                                                                                                         |
| `direction`               | enum     | `outbound` (`sms.sent`) or `inbound` (`sms.received`)                                                                                                               |
| `fromNumber` / `toNumber` | string   | Sender / recipient phone numbers (E.164)                                                                                                                            |
| `content`                 | string   | Message body                                                                                                                                                        |
| `smsType`                 | string   | Internal classification (e.g. `appointment_reminder`, `inbox_reply`, `inbound_sms`, `inbound_mms`, `inbound_rcs`)                                                   |
| `channel`                 | enum     | Messaging channel (e.g. `tells`, `telnyx_sms`, `telnyx_rcs`)                                                                                                        |
| `campaignId`              | UUID     | The campaign the message belonged to, or `null`                                                                                                                     |
| `sentAt`                  | ISO 8601 | When the message was sent / received                                                                                                                                |
| `sentBy`                  | object   | The team member who sent the message (`id`, `name`, `email`, `npn`, `role`, `licensedStates`). `null` for automated/campaign/system sends and all inbound messages. |
| `customer`                | object   | The associated customer (`null` if not linked)                                                                                                                      |

`inbox.conversation_marked_done` [#inboxconversation_marked_done]

Sent when a rep marks an inbox conversation (thread) as done. Carries the
thread and customer ids, who marked it done, and the associated `customer`.

```json
{
  "event_type": "inbox.conversation_marked_done",
  "threadId": "c3d4e5f6-7a80-4b91-8c12-2d4e5f6a7b81",
  "customerId": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "markedDoneAt": "2026-06-25T16:52:10.044Z",
  "markedBy": {
    "memberId": "d4e5f6a7-8b90-4c01-9d22-3e4f5a6b7c82",
    "userId": "b396018f-7d49-4a55-abe5-544174abcaaa",
    "name": "Priya Raman",
    "email": "priya@youragency.com"
  },
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

| Field          | Type     | Description                                                                             |
| -------------- | -------- | --------------------------------------------------------------------------------------- |
| `event_type`   | string   | Always `inbox.conversation_marked_done`                                                 |
| `threadId`     | UUID     | The inbox thread that was closed                                                        |
| `customerId`   | UUID     | The customer the thread belongs to                                                      |
| `markedDoneAt` | ISO 8601 | When the thread was marked done                                                         |
| `markedBy`     | object   | The member who closed it: `memberId`, `userId`, `name`, `email` (`null` if unavailable) |
| `customer`     | object   | The associated customer (`null` if not found)                                           |

`inquiry.callback_scheduled` [#inquirycallback_scheduled]

Sent when a rep resolves a customer inquiry by scheduling an AI callback: the
voice AI will call the customer back to follow up. Carries the inquiry context,
who scheduled it, the estimated callback time, and the associated `customer`
(the same object as [`customer.created`](#customercreated)).

```json
{
  "event_type": "inquiry.callback_scheduled",
  "inquiryId": "e5f6a7b8-9c01-4d22-8e33-4f5a6b7c8d90",
  "customerCampaignId": "4f952597-5c04-4d2c-851e-30f518e2c761",
  "inquiry": "Wants to confirm whether her current cardiologist is in-network before switching plans.",
  "primaryCategory": "plan_benefits",
  "severity": "medium",
  "callbackScheduledFor": "2026-06-30T13:00:00.000Z",
  "callbackRequestedAt": "2026-06-29T21:14:38.512Z",
  "scheduledBy": {
    "id": "7c9e1a2b-3d4e-4f50-8a61-9b0c1d2e3f40",
    "name": "Jordan Smith",
    "email": "jordan@youragency.com",
    "npn": "1234567",
    "role": "agent",
    "licensedStates": ["IL", "IN"]
  },
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

| Field                  | Type               | Description                                                                                                                                                                                                                                                         |
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_type`           | string             | Always `inquiry.callback_scheduled`                                                                                                                                                                                                                                 |
| `inquiryId`            | UUID               | The inquiry the callback resolves                                                                                                                                                                                                                                   |
| `customerCampaignId`   | UUID               | The customer-campaign the inquiry belongs to                                                                                                                                                                                                                        |
| `inquiry`              | string             | The customer's question or request                                                                                                                                                                                                                                  |
| `primaryCategory`      | string             | Inquiry category, if classified (`null` otherwise)                                                                                                                                                                                                                  |
| `severity`             | string             | Inquiry severity, if classified (`null` otherwise)                                                                                                                                                                                                                  |
| `callbackScheduledFor` | ISO 8601 \| `null` | Estimated first-attempt time, respecting the customer's calling window. An estimate at scheduling time; the actual call may be placed later as it's rescheduled around compliance windows. `null` when no compliant window estimate is available at scheduling time |
| `callbackRequestedAt`  | ISO 8601           | When the rep scheduled the callback                                                                                                                                                                                                                                 |
| `scheduledBy`          | object             | The member who scheduled it (`id`, `name`, `email`, `npn`, `role`, `licensedStates`), or `null`                                                                                                                                                                     |
| `customer`             | object             | The associated customer (`null` if not found)                                                                                                                                                                                                                       |

`policy.created` [#policycreated]

Sent when a policy is added to a customer. The payload is the full policy object
plus the associated `customer` (the same object as
[`customer.created`](#customercreated)). Monetary fields are decimal strings,
dates are `YYYY-MM-DD`, and any field with no value is `null`.

```json
{
  "event_type": "policy.created",
  "id": "7a2f9c14-8b3d-4e6f-9a01-2c3d4e5f6a7b",
  "createdAt": "2026-06-17T19:10:44.512Z",
  "updatedAt": "2026-06-17T19:10:44.512Z",
  "customerId": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "policyType": "MAPD",
  "policySubType": "HMO",
  "policyNumber": "MAPD-5582013",
  "applicationId": "APP-99213",
  "carrierId": "c9d0e1f2-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
  "carrierName": "Aetna",
  "planName": "Aetna Medicare Elite (HMO)",
  "planCode": "H1290-036-001",
  "carrierAssignedPolicyId": null,
  "healthSherpaPolicyId": null,
  "sunFireEnrollmentCode": null,
  "hiosId": null,
  "metalLevel": null,
  "status": "Active",
  "applicationApprovalDate": "2026-06-17",
  "effectiveDate": "2026-07-01",
  "terminationDate": null,
  "renewalDate": null,
  "enrollmentDate": "2026-06-17",
  "cancelledDate": null,
  "declineReason": null,
  "declineReasonDescription": null,
  "cancellationReason": null,
  "cancellationReasonDescription": null,
  "electionPeriod": "AEP",
  "gracePeriodStartDate": null,
  "paidThroughDate": null,
  "ffmApplicationId": null,
  "ffmSubscriberId": null,
  "aorFirstName": "Priya",
  "aorLastName": "Raman",
  "aorNpn": "8419302",
  "writingAgentNpn": "8419302",
  "writingAgentName": "Priya Raman",
  "sepType": null,
  "sepCode": null,
  "sepStartDate": null,
  "sepEndDate": null,
  "sepDocumentationReceived": false,
  "sepDocumentationDate": null,
  "sepNotes": null,
  "monthlyPremium": "0.00",
  "deductible": "590.00",
  "outOfPocketMax": "8300.00",
  "subsidyAmount": null,
  "usingSubsidy": false,
  "premiumMode": "Monthly",
  "paymentMode": "ACH",
  "paymentMethod": "ACH / Bank Draft",
  "grossPremium": null,
  "netPremium": null,
  "initialCommission": "611.00",
  "renewalCommission": "305.00",
  "spifAmount": null,
  "policyLives": 1,
  "wasAgent": true,
  "writtenAs": "New Business",
  "isReplacing": null,
  "isRewrite": false,
  "hospitalNetwork": null,
  "pcpNetwork": null,
  "ssbciVerificationRequired": false,
  "dailyBenefit": null,
  "eliminationPeriod": null,
  "benefitPeriod": null,
  "hasCola": false,
  "deathBenefit": null,
  "term": null,
  "maturityDate": null,
  "riders": null,
  "exchangeStatus": null,
  "billingMethod": null,
  "benefitReminder": null,
  "surveyCompleted": false,
  "reasonForPurchase": null,
  "policyNotes": null,
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

Every field below is present on `policy.created` and `policy.updated`. Any field
without a value is `null`.

**Identifiers & plan**

| Field                                                                        | Type     | Description                                                                                            |
| ---------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `event_type`                                                                 | string   | The webhook event: `policy.created` or `policy.updated`. Switch on this to route the event             |
| `id`                                                                         | UUID     | careCycle policy ID                                                                                    |
| `createdAt` / `updatedAt`                                                    | ISO 8601 | When the policy was created / last updated                                                             |
| `customerId`                                                                 | UUID     | The customer the policy belongs to                                                                     |
| `policyType`                                                                 | enum     | Product type, e.g. `MA`, `MAPD`, `PDP`, `MS`, `ACA`, `Life`, `Annuity`, `LTC`                          |
| `policySubType`                                                              | string   | Sub-type within the product family (e.g. `HMO`, `PPO`, `Plan G`)                                       |
| `policyNumber` / `applicationId`                                             | string   | Carrier policy number / application identifier                                                         |
| `carrierId`                                                                  | UUID     | careCycle carrier ID (`null` if unresolved)                                                            |
| `carrierName`                                                                | string   | Insurance carrier name                                                                                 |
| `planName` / `planCode`                                                      | string   | Plan name and code (e.g. `H1290-036-001`)                                                              |
| `carrierAssignedPolicyId` / `healthSherpaPolicyId` / `sunFireEnrollmentCode` | string   | External identifiers from carrier and enrollment systems                                               |
| `hiosId` / `metalLevel`                                                      | string   | ACA plan ID and metal tier (`Bronze`, `Silver`, `Gold`, `Platinum`, `Catastrophic`, `Expanded Bronze`) |

**Status & dates**

| Field                                                                                                                | Type   | Description                                                                                                                |
| -------------------------------------------------------------------------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| `status`                                                                                                             | enum   | Policy status, e.g. `Active`, `Placed`, `Pending`, `Suspended`, `Cancelled`, `Terminated`, `Future Cancel`, `Not Approved` |
| `applicationApprovalDate` / `effectiveDate` / `terminationDate` / `renewalDate` / `enrollmentDate` / `cancelledDate` | date   | Key policy dates (`YYYY-MM-DD`)                                                                                            |
| `declineReason` / `declineReasonDescription`                                                                         | string | Why an application was declined (`Not Approved`)                                                                           |
| `cancellationReason` / `cancellationReasonDescription`                                                               | string | Why a policy was cancelled                                                                                                 |
| `electionPeriod`                                                                                                     | enum   | Enrollment period: `IEP`, `AEP`, `OEP`, `SEP`, `ICEP`, `MA-OEP`                                                            |

**Enrollment & marketplace (ACA)**

| Field                                                  | Type    | Description                                                           |
| ------------------------------------------------------ | ------- | --------------------------------------------------------------------- |
| `gracePeriodStartDate` / `paidThroughDate`             | date    | ACA effectuation dates                                                |
| `ffmApplicationId` / `ffmSubscriberId`                 | string  | Federal marketplace identifiers                                       |
| `exchangeStatus`                                       | enum    | `FFM`, `SBM`, `SBM FP`, `OFF EXCHANGE`, `PRIVATE EXCHANGE`, `UNKNOWN` |
| `sepType` / `sepCode`                                  | string  | Special Enrollment Period type and code                               |
| `sepStartDate` / `sepEndDate` / `sepDocumentationDate` | date    | SEP window and documentation dates                                    |
| `sepDocumentationReceived`                             | boolean | Whether SEP documentation has been received                           |
| `sepNotes`                                             | string  | Free-text SEP notes                                                   |

**Agent of record**

| Field                                     | Type   | Description                  |
| ----------------------------------------- | ------ | ---------------------------- |
| `aorFirstName` / `aorLastName` / `aorNpn` | string | Agent of record name and NPN |
| `writingAgentName` / `writingAgentNpn`    | string | Writing agent name and NPN   |

**Financial**

| Field                                                    | Type                     | Description                                                                              |
| -------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------- |
| `monthlyPremium` / `grossPremium` / `netPremium`         | decimal string           | Premium amounts (gross is before subsidy, net after)                                     |
| `deductible` / `outOfPocketMax`                          | decimal string           | Cost-sharing amounts                                                                     |
| `subsidyAmount` / `usingSubsidy`                         | decimal string / boolean | Subsidy amount and whether it's applied                                                  |
| `premiumMode`                                            | enum                     | `Monthly`, `Quarterly`, `Semi-Annual`, `Annual`                                          |
| `paymentMode`                                            | enum                     | `ACH`, `Credit/ debit card`, `Direct bill`                                               |
| `paymentMethod`                                          | enum                     | `Credit Card`, `Debit Card`, `Check`, `ACH / Bank Draft`, `Money Order`, `Cash`, `Other` |
| `initialCommission` / `renewalCommission` / `spifAmount` | decimal string           | Commission and incentive amounts                                                         |

**Coverage details**

| Field                                                              | Type                                         | Description                                                                                                           |
| ------------------------------------------------------------------ | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `policyLives`                                                      | integer                                      | Number of people covered                                                                                              |
| `wasAgent`                                                         | boolean                                      | Whether an agent was involved in the enrollment                                                                       |
| `writtenAs`                                                        | enum                                         | `New Business`, `Like Plan Change`, `Unlike Plan Change`, `Reinstatement`, `Rewrite`                                  |
| `isReplacing` / `isRewrite`                                        | string / boolean                             | What the policy replaces, and whether it's a rewrite                                                                  |
| `hospitalNetwork` / `pcpNetwork`                                   | string                                       | Medicare network details                                                                                              |
| `ssbciVerificationRequired`                                        | boolean                                      | Whether SSBCI (Special Supplemental Benefits for the Chronically Ill) verification is required, for MA/MAPD plans     |
| `dailyBenefit` / `eliminationPeriod` / `benefitPeriod` / `hasCola` | decimal string / integer / integer / boolean | Long-term care benefit details                                                                                        |
| `deathBenefit` / `term` / `maturityDate` / `riders`                | decimal string / integer / date / string     | Life insurance details. `deathBenefit` is what agents often call "face value"; there is one field for both names      |
| `coverageLevel`                                                    | enum                                         | Final expense coverage structure: `Immediate`, `Graded/ROP`, `Modified Level`, `Standard Level`, or `Preferred Level` |
| `draftDay`                                                         | integer                                      | Day of the month the premium drafts, 1 to 31. A day of the month, not a date                                          |
| `billingMethod` / `benefitReminder` / `surveyCompleted`            | string / date / boolean                      | Compliance and billing tracking                                                                                       |
| `reasonForPurchase` / `policyNotes`                                | string                                       | Free-text notes                                                                                                       |
| `customer`                                                         | object                                       | The associated customer (same shape as `customer.created`; `null` if not found)                                       |

`policy.updated` [#policyupdated]

Sent when a policy is edited, including status changes such as a policy moving
to `Active`, `Cancelled`, or `Not Approved`. The payload is identical in shape to
[`policy.created`](#policycreated) and reflects the policy's state after the
update. `updatedAt` changes on every update.

```json
{
  "event_type": "policy.updated",
  "id": "7a2f9c14-8b3d-4e6f-9a01-2c3d4e5f6a7b",
  "updatedAt": "2026-06-18T15:02:41.880Z",
  "customerId": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
  "status": "Cancelled",
  "cancellationReason": "Moved out of service area",
  "cancelledDate": "2026-06-18",
  "...": "all other policy fields, same shape as policy.created"
}
```

`appointment.scheduled` [#appointmentscheduled]

Sent when an appointment is booked for a customer, whether by the voice AI
during a call, a rep in the dashboard, or the customer via a self-serve
scheduling link. Every `appointment.*` event carries the same base appointment
object plus the nested `customer` (the same object as
[`customer.created`](#customercreated)), `member`, `campaign`, and
`appointmentConfig`, the `actor` that performed the action, and (for some
events) a few extra fields describing the change.

```json
{
  "event_type": "appointment.scheduled",
  "id": "8d1a2b3c-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
  "createdAt": "2026-06-17T19:07:23.709Z",
  "updatedAt": "2026-06-17T19:07:23.709Z",
  "startTime": "2026-06-20T18:00:00.000Z",
  "endTime": "2026-06-20T18:30:00.000Z",
  "timezone": "America/Phoenix",
  "status": "scheduled",
  "bookingSource": "ai_assistant",
  "appointmentMode": "phone_call",
  "title": "30 Min Medicare Review between Priya Raman and Marcus Delacroix",
  "location": null,
  "meetingUrl": null,
  "confirmedAt": null,
  "cancelledAt": null,
  "cancellationReason": null,
  "originCallId": "dca4a483-af54-4899-a804-766ee5812537",
  "actor": {
    "kind": "ai_assistant",
    "callId": "dca4a483-af54-4899-a804-766ee5812537",
    "toolCallId": "call_9fB2xk"
  },
  "member": {
    "id": "d4e5f6a7-8b90-4c01-9d22-3e4f5a6b7c82",
    "name": "Priya Raman",
    "email": "priya@youragency.com",
    "npn": "8419302",
    "role": "agent",
    "licensedStates": ["AZ", "AR"]
  },
  "campaign": {
    "id": "4f952597-5c04-4d2c-851e-30f518e2c761",
    "name": "MA Inbound Receptionist",
    "slug": null,
    "description": null,
    "status": "active",
    "vertical": "medicare",
    "direction": "inbound",
    "kind": "voice_ai",
    "tags": [],
    "startDate": "2026-03-06T00:11:35.256Z",
    "endDate": null
  },
  "appointmentConfig": {
    "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "Medicare Review",
    "appointmentLength": 30,
    "appointmentMode": "phone_call"
  },
  "customer": {
    "id": "b1f7c0e2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
    "...": "full customer object, same shape as customer.created"
  }
}
```

Every field below is present on all `appointment.*` events. Any field without a
value is `null`.

**Appointment**

| Field                     | Type     | Description                                                                                                                                                                                                                                                 |
| ------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_type`              | string   | The webhook event, e.g. `appointment.scheduled`. Switch on this to route the event                                                                                                                                                                          |
| `id`                      | UUID     | careCycle appointment ID (stable across the appointment's lifecycle)                                                                                                                                                                                        |
| `createdAt` / `updatedAt` | ISO 8601 | When the appointment was created / last updated                                                                                                                                                                                                             |
| `startTime` / `endTime`   | ISO 8601 | The scheduled window (UTC; use `timezone` to localize)                                                                                                                                                                                                      |
| `timezone`                | string   | IANA timezone the appointment was booked in (e.g. `America/Chicago`)                                                                                                                                                                                        |
| `status`                  | enum     | `scheduled`, `confirmed`, `cancelled`, `completed`, or `no_show`                                                                                                                                                                                            |
| `bookingSource`           | enum     | How it was booked: `ai_assistant`, `manual`, or `scheduling_page`                                                                                                                                                                                           |
| `appointmentMode`         | enum     | How the appointment takes place. `phone_call` (the voice AI dials the customer) and `agent_phone_call` (an assigned rep dials from the softphone) are the fully supported modes today. `video_call` and `in_person` are defined but not fully supported yet |
| `title`                   | string   | Human-readable appointment title                                                                                                                                                                                                                            |
| `location`                | string   | Physical address for `in_person` meetings. `in_person` is not fully supported yet, so this is `null` in practice                                                                                                                                            |
| `meetingUrl`              | string   | Join URL for `video_call` meetings. `video_call` is not fully supported yet, so this is `null` in practice                                                                                                                                                  |
| `confirmedAt`             | ISO 8601 | When the appointment was confirmed (`null` until confirmed)                                                                                                                                                                                                 |
| `cancelledAt`             | ISO 8601 | When the appointment was cancelled (`null` unless cancelled)                                                                                                                                                                                                |
| `cancellationReason`      | string   | Why the appointment was cancelled (`null` unless cancelled)                                                                                                                                                                                                 |
| `originCallId`            | UUID     | The call the appointment was booked on. Matches the `id` on the [`call.completed`](#callcompleted) event for the same call, so you can join the two. `null` for manual and scheduling-page bookings                                                         |

**Actor, participants & context**

| Field               | Type   | Description                                                                                                                                                                                   |
| ------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actor`             | object | Who performed the action. Always has a `kind` discriminator: `user` (a rep; `userId`, `userName`), `customer` (`customerId`), `ai_assistant` (`callId`, `toolCallId`), or `system` (`reason`) |
| `member`            | object | The team member the appointment is assigned to (`id`, `name`, `email`, `npn`, `role`, `licensedStates`), or `null` if unassigned                                                              |
| `campaign`          | object | The campaign the appointment belongs to (same shape as on `call.completed`), or `null`                                                                                                        |
| `appointmentConfig` | object | The appointment type it was booked under: `id`, `name`, `appointmentLength` (minutes), `appointmentMode`. `null` for older appointments that predate configs                                  |
| `customer`          | object | The associated customer (same shape as `customer.created`)                                                                                                                                    |

`appointment.confirmed` [#appointmentconfirmed]

Sent when a customer confirms their appointment. Identical in shape to
[`appointment.scheduled`](#appointmentscheduled), with `status` set to
`confirmed` and `confirmedAt` populated.

`appointment.rescheduled` [#appointmentrescheduled]

Sent when an appointment is moved to a new time. Identical in shape to
[`appointment.scheduled`](#appointmentscheduled) (the base fields reflect the
new time), plus the previous and new windows:

```json
{
  "event_type": "appointment.rescheduled",
  "id": "8d1a2b3c-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
  "startTime": "2026-06-22T20:00:00.000Z",
  "endTime": "2026-06-22T20:30:00.000Z",
  "fromStartTime": "2026-06-20T18:00:00.000Z",
  "toStartTime": "2026-06-22T20:00:00.000Z",
  "fromEndTime": "2026-06-20T18:30:00.000Z",
  "toEndTime": "2026-06-22T20:30:00.000Z",
  "...": "all other appointment fields, same shape as appointment.scheduled"
}
```

| Field                           | Type     | Description                                            |
| ------------------------------- | -------- | ------------------------------------------------------ |
| `fromStartTime` / `toStartTime` | ISO 8601 | The appointment's start time before and after the move |
| `fromEndTime` / `toEndTime`     | ISO 8601 | The appointment's end time before and after the move   |

`appointment.cancelled` [#appointmentcancelled]

Sent when an appointment is cancelled. Identical in shape to
[`appointment.scheduled`](#appointmentscheduled), with `status` set to
`cancelled` and `cancelledAt` populated, plus the cancellation reason:

```json
{
  "event_type": "appointment.cancelled",
  "id": "8d1a2b3c-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
  "status": "cancelled",
  "cancelledAt": "2026-06-19T15:02:41.880Z",
  "reason": "Customer requested to cancel",
  "...": "all other appointment fields, same shape as appointment.scheduled"
}
```

| Field    | Type   | Description                                                                                                        |
| -------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| `reason` | string | Why the appointment was cancelled (`null` if none was given). Also mirrored on the base `cancellationReason` field |

`appointment.no_show` [#appointmentno_show]

Sent when a customer does not show up for their appointment. Identical in shape
to [`appointment.scheduled`](#appointmentscheduled), with `status` set to
`no_show`.

`appointment.completed` [#appointmentcompleted]

Sent when an appointment takes place and is marked complete (by the call
outcome, a rep, or an automated resolution). Identical in shape to
[`appointment.scheduled`](#appointmentscheduled), with `status` set to
`completed`.

`appointment.member_reassigned` [#appointmentmember_reassigned]

Sent when an appointment is reassigned to a different team member. Identical in
shape to [`appointment.scheduled`](#appointmentscheduled) (the base `member`
reflects the new assignee), plus the previous and new member ids:

```json
{
  "event_type": "appointment.member_reassigned",
  "id": "8d1a2b3c-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
  "fromMemberId": "d4e5f6a7-8b90-4c01-9d22-3e4f5a6b7c82",
  "toMemberId": "f6a7b8c9-0d12-4e34-9f56-7a8b9c0d1e2f",
  "member": {
    "id": "f6a7b8c9-0d12-4e34-9f56-7a8b9c0d1e2f",
    "name": "Jordan Smith",
    "email": "jordan@youragency.com",
    "npn": "1234567",
    "role": "agent",
    "licensedStates": ["IL", "IN"]
  },
  "...": "all other appointment fields, same shape as appointment.scheduled"
}
```

| Field          | Type | Description                                                                     |
| -------------- | ---- | ------------------------------------------------------------------------------- |
| `fromMemberId` | UUID | The member the appointment was assigned to before (`null` if it was unassigned) |
| `toMemberId`   | UUID | The member it is now assigned to (`null` if it was unassigned)                  |
