--- title: Payroll Deductions | Vitable Docs description: How to receive employee deduction events and fetch deduction data for payroll integration. --- Vitable generates payroll deduction statements on a **monthly schedule**. On the 1st of each month, a scheduled process calculates deductions for all employers with active enrollments and fires `employee.deduction_created` webhook events. This page explains how to listen for that event, retrieve the deduction details from the employee resource, and apply them in your payroll system. ## Quick Reference | Event | What It Means | Your Action | Endpoint | | ---------------------------- | ------------------------------------------------------------ | ------------------------------------------- | ------------------------ | | `employee.deduction_created` | Deductions were generated during the monthly statement cycle | Fetch the employee to get deduction details | `GET /v1/employees/{id}` | ## Deduction Flow Overview ``` sequenceDiagram participant V as Vitable API participant P as Partner Note over V: 1st of each month — scheduled deduction generation Note over V: Deductions calculated for all active enrollments V--)P: webhook: employee.deduction_created (per employee) P->>V: GET /v1/employees/{id} V-->>P: 200 Employee with deductions Note over P: Apply deductions to payroll ``` **Flow summary:** 1. On the **1st of each month**, Vitable runs a scheduled process that generates payroll deduction statements for all employers with active enrollments. 2. For each employee with active coverage, Vitable calculates deduction amounts based on their enrolled benefits. 3. Vitable delivers an `employee.deduction_created` webhook per employee to your endpoint. 4. You use the `resource_id` from the webhook payload to fetch the employee and read the `deductions` array. 5. You apply those deductions to your payroll system for the new period. ## Receiving Deduction Events When Vitable delivers an `employee.deduction_created` event, the webhook payload follows the standard format: ``` { "event_id": "wevt_550e8400-e29b-41d4-a716-446655440000", "organization_id": "org_xyz789", "event_name": "employee.deduction_created", "resource_type": "employee", "resource_id": "empl_7c9e6679-7425-40de-944b-e07fc1f90ae7", "created_at": "2026-01-23T14:30:00+00:00" } ``` The `resource_id` is the employee ID (prefixed with `empl_`), and the `resource_type` is `employee`. The `employee.deduction_created` event does **not** fire immediately after enrollment confirmation. Deductions are generated by a monthly scheduled process that runs on the 1st of each month. The event fires once per employee per statement period for all employees with active enrollments. ## Fetching Employee Deductions Deductions are not a standalone API resource — they are a nested property on the employee resource. After receiving the webhook, fetch the employee using `GET /v1/employees/{id}` with the `resource_id` from the payload: Terminal window ``` curl -X GET https://api.vitablehealth.com/v1/employees/empl_7c9e6679-7425-40de-944b-e07fc1f90ae7 \ -H "Authorization: Bearer $VITABLE_API_KEY" \ -H "Content-Type: application/json" ``` The employee response includes a `deductions` array with the current period’s payroll deduction details: | Field | Description | | --------------------------- | ----------------------------------------------------------- | | `deduction_amount_in_cents` | The amount to deduct from the employee’s paycheck, in cents | | `tax_classification` | Tax treatment: `Pre-tax`, `Post-tax`, or `Unknown` | | `frequency` | Deduction frequency (e.g., `monthly`) | | `benefit_name` | The name of the benefit plan this deduction is for | | `deduction_category` | Deduction category (reserved for future use) | | `period_start_date` | Start date of the deduction period (YYYY-MM-DD) | | `period_end_date` | End date of the deduction period (YYYY-MM-DD) | The `deductions` array reflects a snapshot of the current statement period. When a new deduction statement is generated, the previous period’s deductions are replaced. Always fetch fresh data after receiving the webhook rather than relying on cached values. ## Handling Deductions in Your System A typical integration flow looks like this: 1. **Receive** the `employee.deduction_created` webhook and respond with a `2xx` status code immediately. 2. **Fetch** the employee using the `resource_id` to get the current `deductions` array. 3. **Match** the employee in your payroll system using the employee `id` or `reference_id`. 4. **Record** each entry in the `deductions` array as a payroll deduction, noting the `tax_classification` and `frequency`. 5. **Apply** the deductions for the period defined by `period_start_date` and `period_end_date`. Always fetch the employee data after receiving the webhook rather than caching amounts from earlier API calls. Deduction amounts may change when a new statement period is generated. ## Troubleshooting **Missed webhook events** — If your endpoint was down when the event fired, Vitable retries delivery with exponential backoff for up to \~3.4 days. You can also query missed events using `GET /v1/webhook-events` to recover. See [Reliability](/webhooks/reliability/index.md) for full retry details. **Duplicate events** — Your endpoint may receive the same `employee.deduction_created` event more than once. Use the `event_id` field to deduplicate and ensure you do not apply the same deduction twice. **Empty deductions array** — In rare cases, the deductions may not be immediately available when you fetch the employee. If the `deductions` array is empty, implement a short retry with backoff before fetching again. Use `GET /v1/webhook-events/{event_id}/deliveries` to check the delivery status of a specific event if you suspect your endpoint missed it. ## Related Webhooks | Event | Description | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `employee.deduction_created` | Payroll deductions have been generated for an employee. | | `enrollment.accepted` | An enrollment has been accepted and is now active. [Learn more](/embedded_benefits/concepts/enrollment-lifecycle/index.md) | | `enrollment.granted` | An enrollment has been granted. [Learn more](/embedded_benefits/concepts/enrollment-lifecycle/index.md) | | `enrollment.terminated` | An enrollment has been terminated and coverage has ended. [Learn more](/embedded_benefits/concepts/enrollment-lifecycle/index.md) | For the full list of webhook events, see [Webhook Events](/webhooks/events/index.md). ## Related API Endpoints - [`GET /v1/employees/{id}`](/api/resources/employees/methods/retrieve/index.md) — Retrieve employee details including the `deductions` array - [`GET /v1/employees/{id}/enrollments`](/api/resources/employees/methods/list_enrollments/index.md) — List all enrollments for an employee - [`GET /v1/webhook-events`](/api/resources/webhook_events/methods/list/index.md) — Query webhook events to recover missed deliveries - [`GET /v1/webhook-events/{event_id}`](/api/resources/webhook_events/methods/retrieve/index.md) — Retrieve a specific webhook event - [`GET /v1/webhook-events/{event_id}/deliveries`](/api/resources/webhook_events/methods/list_deliveries/index.md) — Check delivery status for a webhook event