Skip to navigation

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

Per-Employee Fields

FieldTypeRequiredRules
first_namestringYes
last_namestringYes
date_of_birthstringYesISO 8601 date
emailstringYesValid email address
phonestringYes10-digit US phone number
reference_idstringNoMust be unique within the payload
address.address_line_1stringNo
address.address_line_2stringNo
address.citystringNo
address.statestringNoValid US state or territory code
address.zipcodestringNo
start_datestringNoISO 8601 date
employee_classstringNoFull Time, Part Time, Temporary, Intern, Seasonal, Individual Contractor
compensation_typestringNoSalary or Hourly

Validation Rules

RuleLimit
Maximum employees per request5,000
reference_id uniquenessMust be unique within a single payload
phone format10-digit US number
state formatValid US state or territory code

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.

POST /v1/employers/{id}/census-sync 202 { data: { accepted_at, employer_id } } webhook: employee.eligibility_granted (per employee) GET /v1/employers/{id}/employees 200 Paginated employee list Async processing begins Partner Vitable API

Flow summary:

  1. You submit a POST /v1/employers/{id}/census-sync request with an array of employees.
  2. Vitable responds with 202 and an acceptance receipt containing accepted_at and employer_id.
  3. Vitable processes each employee asynchronously — creating records and evaluating eligibility.
  4. For each employee that becomes benefits-eligible, Vitable delivers an employee.eligibility_granted webhook.
  5. You verify the final state by calling GET /v1/employers/{id}/employees.

The 202 response confirms Vitable accepted your request for processing. It does not mean employees have been created yet. Always use webhooks or the list employees endpoint to confirm outcomes.

There is no sync-completion webhook. There is no single event that signals the entire census sync is done. Listen for individual employee.eligibility_granted events to track processing progress.

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

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

After submitting a census sync, you have two ways to track what happened: webhooks and the list employees endpoint.

Receiving Webhooks

As Vitable processes each employee, it evaluates their benefits eligibility. 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}.

The employee.eligibility_granted event signals that an employee is now eligible for benefits and their enrollment window is open. For the full employee status model and related events, see the Employee Lifecycle guide.

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
ParameterDefaultDescription
page1Page number
limit20Number 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

This diagram shows the complete sequence for a successful census sync, from submission through employee verification.

POST /v1/employers/{id}/census-sync (N employees) 202 { data: { accepted_at, employer_id } } webhook: employee.eligibility_granted (employee 1) webhook: employee.eligibility_granted (employee 2) GET /v1/employers/{id}/employees?page=1&limit=20 200 Paginated employee list (total: N) Processing employee 1 of N Processing employee 2 of N ... (remaining employees) Partner Vitable API

Step-by-step:

  1. You send a census sync with N employees.
  2. Vitable returns the acceptance receipt immediately.
  3. For each processed employee who becomes benefits-eligible, Vitable delivers an employee.eligibility_granted webhook.
  4. You call the list employees endpoint to confirm all N records exist.

Handling Errors and Partial Failures

Not every census sync succeeds cleanly. The following flowchart shows how validation and processing errors surface.

alt [Payload invalid] [Payload valid] POST /v1/employers/{id}/census-sync 400 Validation Error (no processing) 202 Accepted webhook: employee.eligibility_granted (valid employees) Per-employee async processing Partner Vitable API

Summary:

  • If the payload structure is invalid (e.g., missing required fields, exceeding 5,000 employees), you receive a 400 error immediately — no processing occurs.
  • If the payload is accepted, individual employees may still fail during async processing (e.g., a duplicate reference_id matching an existing employee). Successfully processed employees are created; failed ones are skipped.
  • You will only receive employee.eligibility_granted webhooks for employees that were successfully created and evaluated as eligible.

Troubleshooting

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

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

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

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

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.

There is no webhook for failed employee records in a census sync. The only way to detect partial failures is to compare the expected employee count against the actual count returned by the list employees endpoint.

EventDescription
employee.eligibility_grantedAn employee has been evaluated as eligible for benefits. View event details

The employee.eligibility_granted event is the primary signal that census sync processing completed for a given employee. For the full set of employee-related events — including employee.eligibility_terminated and employee.deactivated — see the Employee Lifecycle guide.