> ## Documentation Index
> Fetch the complete documentation index at: https://getprescience.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Census

> Learn how to submit a census: the member schema, validation rules, and quoting vs enrollment requirements.

The census is the input to everything: quotes are rated from it, enrollments materialize it into the live plan, and ongoing syncs keep it true. You already have all of this data; it's your employee roster plus dependents.

`PUT /groups/{groupId}/census` replaces the full census. Members are **upserted by `email`** when present, otherwise by `externalId`, so re-pushing your roster is always safe and idempotent.

## Member schema

```json theme={null}
{
  "externalId": "emp_0008",
  "firstName": "Grace",
  "lastName": "Okafor",
  "email": "grace@acme.com",
  "dob": "1990-07-03",
  "zip": "94110",
  "sexAtBirth": "female",
  "employmentType": "full_time",
  "hireDate": "2023-07-15",
  "status": "active",
  "dependents": [
    { "relationship": "spouse", "dob": "1989-08-12", "name": "Femi Okafor" }
  ]
}
```

| Field                   | Type         | Required              | Notes                                                                                                                            |
| ----------------------- | ------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `externalId`            | string       | No                    | Your employee ID. Upsert key when `email` is absent.                                                                             |
| `firstName`, `lastName` | string       | At enrollment         | Not needed to quote.                                                                                                             |
| `email`                 | string       | At enrollment         | Primary upsert key. Members are invited to the Prescience app via this address after launch.                                     |
| `dob`                   | `YYYY-MM-DD` | One of `dob` \| `age` | Preferred; exact ages rate more accurately than integer ages.                                                                    |
| `age`                   | integer      | One of `dob` \| `age` | Fallback when you don't store DOB.                                                                                               |
| `zip`                   | string       | **Yes**               | 5-digit home ZIP. Drives the geographic rating factor.                                                                           |
| `sexAtBirth`            | enum         | No                    | `male` \| `female` \| `other`.                                                                                                   |
| `employmentType`        | enum         | No                    | `full_time` \| `part_time` \| `contractor`.                                                                                      |
| `hireDate`              | `YYYY-MM-DD` | No                    |                                                                                                                                  |
| `status`                | enum         | No                    | `active` (default) \| `terminated`. Terminated members are excluded from rating.                                                 |
| `dependents`            | array        | No                    | Max 6 per member. Each: `relationship` (required: `spouse` \| `domestic_partner` \| `child` \| `other`), optional `dob`, `name`. |

**Limits:** up to 10,000 members per census, 6 dependents per member.

## Quoting vs enrollment requirements

<Tabs>
  <Tab title="To quote">
    Per member: **`zip` + one of `dob` | `age`.** That's it.

    This is deliberate: you can generate a quote from the minimal data every HR system has, before asking anyone for names or emails. Dependent `dob`s sharpen the rating (a spouse without one is rated at the employee's age; a child without one is rated as a 10-year-old), but they're optional.
  </Tab>

  <Tab title="To enroll">
    Everything quoting needs, **plus `firstName`, `lastName`, and `email` for every active member.**

    This is enforced at enrollment time, not at census upload. `POST /enrollments` returns `400 invalid_request` with one `details` entry per failing member:

    ```json theme={null}
    {
      "error": "invalid_request",
      "message": "2 members are missing fields required for enrollment.",
      "details": [
        { "index": 3, "field": "email", "message": "email is required for enrollment" },
        { "index": 9, "field": "lastName", "message": "lastName is required for enrollment" }
      ]
    }
    ```
  </Tab>
</Tabs>

## Per-row errors: bad rows never block good ones

A census write is row-by-row. Valid rows are stored; invalid rows are rejected and reported with their index. A 142-row upload with one bad ZIP stores 141 members:

```json theme={null}
{
  "groupId": "grp_8c2f41d09a3e",
  "received": 142,
  "accepted": 141,
  "memberCount": 141,
  "errors": [
    { "index": 7, "field": "zip", "message": "zip must be a 5-digit ZIP code" }
  ],
  "warnings": [
    "3 members missing email (required before enrollment)"
  ]
}
```

* **`errors`**: rows that were rejected. Fix and re-`PUT`; upserts make re-sending the clean rows harmless.
* **`warnings`**: non-blocking issues, today chiefly members missing `email`. They quote fine but will fail enrollment.

<Tip>
  Treat `accepted < received` as a sync alert in your integration, not a hard failure. The group can still be quoted with the accepted members.
</Tip>

## Reading the census back

`GET /groups/{groupId}/census` returns what's stored, each member with a server-assigned `memberId`:

```json theme={null}
{
  "members": [
    {
      "memberId": "mem_c4a91f27e83d",
      "externalId": "emp_0001",
      "firstName": "Jordan",
      "lastName": "Reyes",
      "email": "jordan@acme.com",
      "dob": "1992-03-14",
      "zip": "94110",
      "employmentType": "full_time",
      "hireDate": "2024-03-01",
      "status": "active"
    }
  ],
  "count": 12
}
```

Keep `memberId` mapped to your employee record; it's the handle for single-member updates (`PATCH /members/{memberId}`) in [census sync](/guides/census-sync).

<Info>
  Census intake is enrollment and eligibility data. Before live mode, a BAA and data processing agreement are executed covering exactly this data. See [Compliance](/resources/compliance).
</Info>
