Census Sync
How to submit employee data in bulk via census sync, monitor async processing, and handle validation errors.
Census sync replaces an employer’s entire employee roster. When you submit a new sync, the system matches existing employees using reference_id and other available information. Employees included in the payload are created or updated; employees omitted are deactivated. This is not an append operation.
You send a single POST /v1/employers/{id}/census-sync request containing up to 5,000 employees, and Vitable processes them asynchronously. The response is an acceptance receipt — not the final result. You track outcomes through webhooks and the GET /v1/employers/{id}/employees endpoint.
This guide covers the request format, the async processing model, how to verify results, and what to do when things go wrong.
Quick Reference
Section titled “Quick Reference”Per-Employee Fields
Section titled “Per-Employee Fields”| Field | Type | Required | Rules |
|---|---|---|---|
first_name | string | Yes | |
last_name | string | Yes | |
date_of_birth | string | Yes | ISO 8601 date |
email | string | Yes | Valid email address |
phone | string | Yes | 10-digit US phone number |
reference_id | string | No | Must be unique within the payload |
address.address_line_1 | string | No | |
address.address_line_2 | string | No | |
address.city | string | No | |
address.state | string | No | Valid US state or territory code |
address.zipcode | string | No | |
start_date | string | No | ISO 8601 date |
employee_class | string | No | Full Time, Part Time, Temporary, Intern, Seasonal, Individual Contractor |
compensation_type | string | No | Salary or Hourly |
Validation Rules
Section titled “Validation Rules”| Rule | Limit |
|---|---|
| Maximum employees per request | 5,000 |
reference_id uniqueness | Must be unique within a single payload |
phone format | 10-digit US number |
state format | Valid US state or territory code |
Understanding the Async Flow
Section titled “Understanding the Async Flow”Census sync is fully asynchronous. When you submit a request, Vitable validates the payload structure and immediately returns an acceptance receipt. The actual employee creation and eligibility evaluation happen in the background.
sequenceDiagram
participant P as Partner
participant V as Vitable API
P->>V: POST /v1/employers/{id}/census-sync
V-->>P: 202 { data: { accepted_at, employer_id } }
Note over V: Async processing begins
V--)P: webhook: employee.eligibility_granted (per employee)
P->>V: GET /v1/employers/{id}/employees
V-->>P: 200 Paginated employee list
Flow summary:
- You submit a
POST /v1/employers/{id}/census-syncrequest with an array of employees. - Vitable responds with
202and an acceptance receipt containingaccepted_atandemployer_id. - Vitable processes each employee asynchronously — creating records and evaluating eligibility.
- For each employee that becomes benefits-eligible, Vitable delivers an
employee.eligibility_grantedwebhook. - You verify the final state by calling
GET /v1/employers/{id}/employees.
Submitting a Census Sync
Section titled “Submitting a Census Sync”Send a POST /v1/employers/{id}/census-sync request with an employees array:
{ "employees": [ { "reference_id": "EMP-001", "first_name": "Jane", "last_name": "Doe", "date_of_birth": "1990-05-15", "email": "jane.doe@example.com", "phone": "5551234567", "address": { "address_line_1": "123 Main St", "address_line_2": "Apt 4B", "city": "Austin", "state": "TX", "zipcode": "78701" }, "start_date": "2026-01-15", "employee_class": "Full Time", "compensation_type": "Salary" }, { "reference_id": "EMP-002", "first_name": "John", "last_name": "Smith", "date_of_birth": "1985-11-22", "email": "john.smith@example.com", "phone": "5559876543", "address": { "address_line_1": "456 Oak Ave", "city": "Dallas", "state": "TX", "zipcode": "75201" }, "start_date": "2026-02-01", "employee_class": "Part Time", "compensation_type": "Hourly" } ]}A successful response looks like this:
{ "data": { "accepted_at": "2026-03-25T14:30:00+00:00", "employer_id": "empr_550e8400-e29b-41d4-a716-446655440000" }}The accepted_at timestamp marks when Vitable acknowledged the request. Store this alongside the employer_id so you can correlate it with incoming webhooks.
Employee Matching and Processing
Section titled “Employee Matching and Processing”The system matches employees using reference_id and other available information to preserve existing records and enrollment history across syncs. Matched employees are updated with the new data; unmatched entries create new employee records.
Previously deactivated employees are reactivated if they reappear in a subsequent sync.
Required fields per employee: first_name, last_name, date_of_birth, email, phone
Optional fields: reference_id, address, start_date, employee_class, compensation_type
Monitoring Progress
Section titled “Monitoring Progress”After submitting a census sync, you have two ways to track what happened: webhooks and the list employees endpoint.
Receiving Webhooks
Section titled “Receiving Webhooks”As Vitable processes each employee, it evaluates eligibility based on the employer’s eligibility policy. When an employee becomes benefits-eligible, you receive an employee.eligibility_granted webhook:
{ "event_id": "wevt_550e8400-e29b-41d4-a716-446655440000", "organization_id": "org_xyz789", "event_name": "employee.eligibility_granted", "resource_type": "employee", "resource_id": "empl_7c9e6679-7425-40de-944b-e07fc1f90ae7", "created_at": "2026-03-25T14:31:00+00:00"}Use the resource_id to fetch the employee’s full record via GET /v1/employees/{id}.
Verifying via the List Employees Endpoint
Section titled “Verifying via the List Employees Endpoint”You can also poll GET /v1/employers/{id}/employees to see which employees have been created. This endpoint returns a paginated list:
GET /v1/employers/{id}/employees?page=1&limit=20| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number |
limit | 20 | Number of employees per page |
The response includes pagination metadata:
{ "data": [...], "pagination": { "page": 1, "limit": 20, "total": 150, "total_pages": 8 }}Compare pagination.total against the number of employees you submitted to confirm all records were created.
Walking Through the Happy Path
Section titled “Walking Through the Happy Path”This diagram shows the complete sequence for a successful census sync, from submission through employee verification.
sequenceDiagram
participant P as Partner
participant V as Vitable API
P->>V: POST /v1/employers/{id}/census-sync (N employees)
V-->>P: 202 { data: { accepted_at, employer_id } }
Note over V: Processing employee 1 of N
V--)P: webhook: employee.eligibility_granted (employee 1)
Note over V: Processing employee 2 of N
V--)P: webhook: employee.eligibility_granted (employee 2)
Note over V: ... (remaining employees)
P->>V: GET /v1/employers/{id}/employees?page=1&limit=20
V-->>P: 200 Paginated employee list (total: N)
Step-by-step:
- You send a census sync with N employees.
- Vitable returns the acceptance receipt immediately.
- For each processed employee, Vitable delivers an
employee.eligibility_grantedwebhook (timing depends on the employer’s eligibility policy and any waiting period). - You call the list employees endpoint to confirm all N records exist.
Handling Errors and Partial Failures
Section titled “Handling Errors and Partial Failures”Not every census sync succeeds cleanly. The following flowchart shows how validation and processing errors surface.
sequenceDiagram
participant P as Partner
participant V as Vitable API
P->>V: POST /v1/employers/{id}/census-sync
alt Payload invalid
V-->>P: 400 Validation Error (no processing)
else Payload valid
V-->>P: 202 Accepted
Note over V: Per-employee async processing
V--)P: webhook: employee.eligibility_granted (valid employees)
end
Summary:
- If the payload structure is invalid (e.g., missing required fields, exceeding 5,000 employees), you receive a
400error immediately — no processing occurs. - If the payload is accepted, individual employees may still fail during async processing (e.g., a duplicate
reference_idmatching an existing employee). Successfully processed employees are created; failed ones are skipped. - You will only receive
employee.eligibility_grantedwebhooks for employees that were successfully created and evaluated as eligible.
Troubleshooting
Section titled “Troubleshooting”Exceeding the batch limit
Section titled “Exceeding the batch limit”Each census sync request accepts a maximum of 5,000 employees. If your payload exceeds this limit, the entire request is rejected with a 400 error. Split larger datasets into multiple requests.
Duplicate reference_id values within a payload
Section titled “Duplicate reference_id values within a payload”Every reference_id in a single request must be unique. If you include the same reference_id twice, the request fails validation. Deduplicate your data before submitting.
Invalid phone numbers
Section titled “Invalid phone numbers”The phone field must be a 10-digit US phone number (digits only, no dashes or spaces). Values like 555-123-4567 or +15551234567 are rejected. Send 5551234567 instead.
Invalid state codes
Section titled “Invalid state codes”The state field must be a valid US state or territory code (e.g., TX, CA, PR). Full state names like Texas are not accepted.
Partial failures
Section titled “Partial failures”When some employees in a batch are valid and others are not, Vitable processes the valid ones and skips the invalid ones. You will not receive an explicit error notification for skipped employees. To detect partial failures, compare the pagination.total from GET /v1/employers/{id}/employees against the number of employees you submitted. If the count is lower than expected, review your source data for the issues described above and resubmit the corrected records.
Related Webhooks
Section titled “Related Webhooks”| Event | Description |
|---|---|
employee.eligibility_granted | An employee has been evaluated as eligible for benefits. View event details |
Related API Endpoints
Section titled “Related API Endpoints”POST /v1/employers/{id}/census-sync— Submit employee data for async processingGET /v1/employers/{id}/employees— List employees for an employer (paginated)GET /v1/employees/{id}— Retrieve a single employee recordGET /v1/webhook-events— Query webhook events for troubleshootingGET /v1/webhook-events/{event_id}/deliveries— Check delivery status for a specific event