# People, families and merges

Read a person's close family and tree, add or remove relatives, merge and unmerge duplicates, and resolve conflicts.


Beyond creating and editing people, the API covers the work you do on relationships in the app: linking relatives, reading the tree, merging duplicates and undoing a merge, and resolving conflicts.

## Read a person's close family

```bash
curl https://kleiobase.com/api/v1/workspaces/WORKSPACE_ID/people/PERSON_ID/family \
  -H "Authorization: Bearer kb_live_YOUR_KEY"
```

You get `parents`, `partners` and `children`. Each entry carries the `family_id` it comes through and, for parents and children, the `pedigree` of the link (`null` means biological). A partner entry whose `person_id` is `null` is a family the person heads alone.

## Read the tree

`GET .../people/{person_id}/tree` walks the tree from a person and returns `nodes` (people), `unions` (families) and `edges` between them. It is data only, with no layout.

- `direction`: `ancestors`, `descendants` or `both` (default `both`).
- `depth`: 1 to 8 generations (default 4). `truncated` is `true` when relatives exist beyond the depth.

## Add or remove a relative

Link an existing person, or create a new one in the same request with `new_person`:

```bash
curl -X POST https://kleiobase.com/api/v1/workspaces/WORKSPACE_ID/people/PERSON_ID/relatives \
  -H "Authorization: Bearer kb_live_YOUR_KEY" \
  -H "Idempotency-Key: add-father-1" \
  -H "Content-Type: application/json" \
  -d '{"type": "parent", "new_person": {"given_name": "Josef", "surname": "Novak", "gender": "M"}}'
```

`type` is `partner`, `parent`, `child`, `sibling` or `associate`. The same rules apply as in the app, including your plan's person limit (`403 forbidden`). You get `201` when a person was created and `200` when an existing one was linked. Either way the body has the relative's `person_id`.

To remove a link, send `DELETE` to the same URL with `{"person_id": "...", "type": "parent"}`. The people themselves are not deleted.

To change a couple's relationship status or a family event such as a marriage, use `PATCH .../families/{family_id}`.

## Records a person should have

`GET .../people/{person_id}/expected-records` lists research targets, such as a census the person should appear in, highest priority first. To dismiss one, send `PATCH .../expected-records/{expected_record_id}` with `{"dismissed": true}`.

## Merge and unmerge

Merging two people (`POST .../people/{person_id}/merge`) and accepting a match (`POST .../matches/{match_id}/accept`) both return a `match_id`. Keep it: it is how you undo the merge.

```bash
curl -X POST https://kleiobase.com/api/v1/workspaces/WORKSPACE_ID/people/SURVIVOR_ID/unmerge \
  -H "Authorization: Bearer kb_live_YOUR_KEY" \
  -H "Idempotency-Key: unmerge-1" \
  -H "Content-Type: application/json" \
  -d '{"match_id": "MATCH_ID"}'
```

The person in the path must be the merge's survivor. The response lists `restored_person_ids`.

### Merge a group of duplicates

`POST .../matches/merge-group` merges 2 to 20 people into one survivor:

```json
{ "person_ids": ["ID_1", "ID_2", "ID_3"], "survivor_id": "ID_1" }
```

The response has one `match_id` per merged person. Unmerging any one of them undoes the whole group. If a later person cannot be merged, the earlier merges stand and that person is listed in `failed`.

## Resolve conflicts

`GET .../conflicts` lists them. Two kinds can be resolved through the API, as in the app:

- **A person with more than one birth family:** `POST .../conflicts/resolve` with `action` `keep_family` (keep `family_id` as the birth family and mark the others adopted) or `change_pedi` (set `pedigree` on the link to `family_id`).
- **Spelling variants of a fact**, such as an occupation written two ways: `POST .../conflicts/fact-variants/resolve` folds `folded_values` into `keep_value`, and `pin_values` keeps values apart as genuinely different facts.

Both return the person's conflicts after the change.

Canonical: https://kleiobase.com/developers/docs/people-and-families
