# Records API

> Subjects, normalized records, categories, and change feeds.

## List pseudonymous users with active share consent

`GET /users` on `https://api.finchnode.com/api/v1`

Parameters:

- `limit` (query, integer)
- `cursor` (query, string): Opaque cursor. Pass nextCursor back to the endpoint that returned it, for the same subject and category; meta.changeCursor starts the change feed. Don't construct or edit it.
- `offset` (query, integer): Legacy offset pagination. Prefer cursor.

Responses:

- `200`: Cursor-paginated app- and environment-scoped users.
- `400`: Request validation failed.
- `401`: API key is missing, invalid, or revoked.
- `429`: Request budget exceeded.

## Retrieve a consent-filtered normalized health-record snapshot

`GET /users/{subject}/records` on `https://api.finchnode.com/api/v1`

Parameters:

- `subject` (path, string, required): Stable within one application and unlinkable across applications.
- `categories` (query, string): Comma-separated consent-category subset. Omit for all authorized categories.

Responses:

- `200`: Non-cacheable snapshot with completeness and freshness metadata.
- `400`: Request validation failed.
- `401`: API key is missing, invalid, or revoked.
- `403`: App scope, environment, or consent does not authorize the request.
- `404`: App-scoped resource does not exist.
- `410`: Consent or session is no longer active.
- `429`: Request budget exceeded.

## List records in one consent category

`GET /users/{subject}/records/{category}` on `https://api.finchnode.com/api/v1`

Stable record IDs and cursor pagination make this endpoint preferable for production ingestion. Save meta.changeCursor after an initial full read.

Parameters:

- `subject` (path, string, required): Stable within one application and unlinkable across applications.
- `category` (path, string, required)
- `limit` (query, integer)
- `cursor` (query, string): Opaque cursor. Pass nextCursor back to the endpoint that returned it, for the same subject and category; meta.changeCursor starts the change feed. Don't construct or edit it.

Responses:

- `200`: One page of normalized records.
- `400`: Request validation failed.
- `401`: API key is missing, invalid, or revoked.
- `403`: App scope, environment, or consent does not authorize the request.
- `404`: App-scoped resource does not exist.
- `410`: Consent or session is no longer active.

## Read incremental upserts and deletion tombstones

`GET /users/{subject}/records/{category}/changes` on `https://api.finchnode.com/api/v1`

Pass the changeCursor returned by the category snapshot. Apply changes in sequence order. A delete change has record null and must remove the stable recordId locally. Upserts may have record null if a later source deletion occurred before this historical page was read.

Parameters:

- `subject` (path, string, required): Stable within one application and unlinkable across applications.
- `category` (path, string, required)
- `limit` (query, integer)
- `cursor` (query, string): Opaque cursor. Pass nextCursor back to the endpoint that returned it, for the same subject and category; meta.changeCursor starts the change feed. Don't construct or edit it.

Responses:

- `200`: Incremental change page.
- `400`: Request validation failed.
- `401`: API key is missing, invalid, or revoked.
- `403`: App scope, environment, or consent does not authorize the request.
- `404`: App-scoped resource does not exist.
- `410`: Consent or session is no longer active.
