# Relationships

> Link people, organisations, and projects with context.

## Affiliations preserve history

Call `affiliations_set` to connect a contact and an organisation:

```json
{
  "contact_id": "01900000-0000-7000-8000-000000000001",
  "organisation_id": "01900000-0000-7000-8000-000000000002",
  "role": "Researcher",
  "starts_on": "2026-10-01",
  "is_primary": true,
  "idempotency_key": "maya-studio-001"
}
```

Both IDs, a role, and an operation key are required for creation. `starts_on`, `ends_on`, and `is_primary` are optional. Dates must be valid `YYYY-MM-DD` values; an end cannot precede a start. At most one non-archived affiliation per contact can be marked primary. Clear the previous primary explicitly before choosing another.

Identical additions with the same contact, organisation, role, and start date reuse the existing relationship. A different employment period can be a separate affiliation. No record is automatically merged or reassigned.

## Project participants

Call `participants_set` with `project_id`, exactly one of `contact_id` or `organisation_id`, a `role`, and `idempotency_key`. Optional `context` holds up to 10,000 characters of project-specific notes.

A project has at most one participant record for a particular contact or organisation. Repeating the same addition is safe. To change role or context, use the existing relationship's ID and revision rather than creating another participant.

## List, edit, remove, and restore

`affiliations_list` requires `contact_id`; `participants_list` requires `project_id`. Both support `include_archived`, `page` (1–10,000), and `per_page` (1–50; default 20), and return the plural collection plus pagination.

To edit with either `*_set` tool, provide `id`, `expected_revision`, `idempotency_key`, and only the mutable fields you want to change. Do not resubmit the endpoint IDs. Endpoints are immutable; remove and create a different relationship to change them.

```json
{
  "id": "01900000-0000-7000-8000-000000000003",
  "expected_revision": 1,
  "role": "Advisor",
  "idempotency_key": "relationship-role-001"
}
```

`affiliations_remove` and `participants_remove` take `id`, `expected_revision`, and `idempotency_key`. Removal archives the relationship; it does not delete either endpoint or erase history. Calling `*_set` with the archived relationship's ID and current revision restores it, provided its endpoints are active.

All mutations return `affiliation` or `participant`, plus `replayed`. They enforce workspace permissions, revision checks, retry protection, and audit attribution. New or restored links require active endpoints in the same workspace. Historical links remain recorded when an endpoint is archived.

## Search through relationships

Find contacts with `contacts_search` using `organisation_id` or `project_id`. Find projects with `projects_search` using participant `contact_id` or `organisation_id`. Find organisations with `organisations_search` using `project_id`. These filters use non-archived relationships and combine with other filters. The referenced parent must be accessible; `include_archived` permits an archived parent but does not reactivate removed relationships.
