> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.vitablehealth.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.vitablehealth.com/_mcp/server.

# Employee Enrollment

> Set up the employee benefits experience — embed the enrollment widget and handle enrollment events.

This guide walks you through setting up the employee enrollment experience — from generating access tokens to embedding the benefits widget and monitoring enrollment status.

**Prerequisites:**

* An employer with employees synced and eligibility granted — see [Employer Onboarding](/embedded_benefits/guides/employer-onboarding)
* A webhook endpoint configured to receive events — see [Webhooks](/webhooks)

## What Your Employees Will See

Before diving into the integration, here is what happens inside the embedded widget when an employee enrolls:

1. Employee opens the enrollment UI — you receive an `enrollment.started` event
2. Employee selects a plan and confirms — you receive both `enrollment.elected` and `enrollment.accepted` events
3. If the employee declines — you receive an `enrollment.waived` event instead

`enrollment.elected` and `enrollment.accepted` fire together from the same action — the employee selects a plan, signs, and confirms in a single step. There is no separate confirmation step after plan selection.

In some cases, enrollments are auto-granted by the system. When this happens, you receive an `enrollment.granted` event. The employee still needs to make an election.

> **Tip**
>
> The enrollment flow is handled entirely within the embedded widget. Your integration only needs to listen for webhook events to track enrollment progress.

#### Set Up Authentication

To load the widget for a specific employee, you need a bound access token. This token scopes widget access to that employee.

```bash
curl -X POST https://api.vitablehealth.com/v1/auth/access-tokens \
  -H "Authorization: Bearer $VITABLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "bound_entity": {
      "type": "employee",
      "id": "empl_abc123"
    }
  }'
```

> **Warning**
>
> Bound access tokens must be generated **server-side** and should be short-lived. Never expose your API key in client-side code. The token scopes widget access to a specific employee.

See [Authentication](/getting-started/authentication) for full details on token types, lifetimes, and rotation.

See the [Issue Access Token endpoint](/api/auth/issue-access-token) for the full request and response schema.

#### Embed the Employee Dashboard

Use the Vitable Drops SDK to embed the employee dashboard widget in your application:

```typescript
import { VitableConnectProvider, EmployeeViewWidget } from "@vitable-inc/drops/react";

<VitableConnectProvider baseUrl={widgetUrl} fetchToken={fetchTokenFn}>
  <EmployeeViewWidget height="800px" />
</VitableConnectProvider>
```

The widget handles the entire enrollment flow — plan selection, waiving, e-signatures, and dependent management.

For the complete integration guide with React, Python, and Node.js examples, see the [Employee Dashboard Widget](/drops/employee-dashboard) documentation.

#### Monitor Enrollment Status

Track enrollment progress by fetching employees with their current enrollment status:

```bash
curl "https://api.vitablehealth.com/v1/employers/{employer_id}/employees" \
  -H "Authorization: Bearer $VITABLE_API_KEY"
```

Enrollment statuses exposed via the API:

| Status     | Meaning                                               |
| ---------- | ----------------------------------------------------- |
| `pending`  | Enrollment opportunity exists, employee has not acted |
| `enrolled` | Employee has selected a plan and enrollment is active |
| `waived`   | Employee declined the benefit                         |
| `inactive` | Coverage has ended (terminated)                       |

See the [List Employees endpoint](/api/employers/list-employees) for the full response schema.

#### Handle Terminations

When coverage ends — whether due to an employee leaving, an admin action, or a qualifying life event — you receive an `enrollment.terminated` webhook event. The enrollment status transitions to `inactive`.

For the complete enrollment state machine and all transitions, see the [Enrollment Lifecycle](/embedded_benefits/concepts/enrollment-lifecycle) concept page.

## Troubleshooting

* **Widget shows authentication error:** Verify the bound access token is valid, not expired, and scoped to the correct employee. Tokens must be generated server-side — never pass your API key to the client.
* **No enrollment webhooks firing:** Confirm your webhook endpoint is registered and reachable. Check the [Webhooks Events](/webhooks/events) page for the full list of enrollment events.
* **Employee status stuck on `pending`:** The employee has not completed the enrollment flow in the widget yet. `pending` means the enrollment opportunity exists but no election has been made.

## What's Next

Proceed to [Benefits Administration](/embedded_benefits/guides/benefits-administration) for ongoing workforce management — roster updates, lifecycle events, and payroll deductions.

## Related API Endpoints

* [`POST /v1/auth/access-tokens`](/api/auth/issue-access-token) — Create a bound access token
* [`GET /v1/employers/{id}/employees`](/api/employers/list-employees) — List employees with enrollment status
* [`GET /v1/employees/{id}/enrollments`](/api/employees/list-enrollments) — List enrollments for an employee