# List persons by role

`GET /v1/persons`

Persons with their dated roles. `role` restricts to persons holding that role
at `valid_at` (default: request time); `team_id` restricts to roles attached
to that team. Stable order: `name` ascending, then `id` ascending. `known_at`
limits identity decisions and role revisions to those recorded by the cutoff;
an identifier that is an alias at the cutoff (merged into another person by a
decision recorded by then and not reversed) is not listed as a separate person,
although `GET /v1/persons/{id}` still resolves it. An `entities` grant naming
competitions lists only persons linked to one of them: through a membership (any
role, any date) at a team that entered or played in the competition, or a fixture
of it they officiated.

Parameters:
- `role` (query, enum, optional): Role held at `valid_at`. One of: `coach`, `player`, `referee`.
- `team_id` (query, string, optional): Team identifier (`tm_<digits>`). A retired identifier filters by the team it resolves to at `known_at`, and `resolution.team_id` says so.
- `valid_at` (query, timestamp, optional): Business-effective instant (UTC); default is the request time.
- `known_at` (query, timestamp, optional): Knowledge cutoff (UTC); the answer reflects only what OddsFinder had recorded by this instant. Default is the request time. Must not be in the future.
- `cursor` (query, string, optional): Opaque page cursor from a previous `page.next_cursor`; filters must be repeated unchanged.
- `limit` (query, integer, optional): Maximum items per page.

Returns `200`: One page of persons.
- `items` (array of objects):  See [the person object](obj-Person.md).
- `page` (object)
  - `next_cursor` (string, nullable): Cursor for the next page, or `null` on the last page.
  - `limit` (integer)
- `knowledge` (object): The effective knowledge cutoff of the response. Under a grant freshness delay it is never later than the request time minus the delay, whatever `known_at` asked for.
  - `known_at` (timestamp): RFC 3339 instant in UTC with `Z` suffix; optional fractional seconds up to microseconds.
  - `as_requested` (boolean): True when the caller supplied `known_at`; false when it defaulted to the request time.
- `resolution` (object): How each identifier filter of a list read resolved at `known_at`, by parameter name; present when a supplied filter names a registered entity the caller is served and its grant admits (an entity outside a competition restriction, or one the single read answers as unknown, is not echoed and the filter applies as given). A retired identifier (`status` `alias`) filters, and for a competition is authorized, as its `canonical_id`; list items themselves never carry a resolution.
  - `team_id` (object): How the requested identifier resolved. Present whenever the requested identifier is not the canonical one, and optional otherwise.
    - `requested_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `canonical_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `status` (enum): `canonical`: the requested identifier is the identity itself; `alias`: it was retired by a merge decision and resolves to `canonical_id`. One of: `canonical`, `alias`.
    - `decision_id` (string, nullable): Identifier of a merge or reversal decision (`dec_<digits>`), a record you can cite.
    - `decided_at` (timestamp, nullable): A `Timestamp`, or `null` when unknown; the owning object says why.
  - `competition_id` (object): How the requested identifier resolved. Present whenever the requested identifier is not the canonical one, and optional otherwise.
    - `requested_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `canonical_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `status` (enum): `canonical`: the requested identifier is the identity itself; `alias`: it was retired by a merge decision and resolves to `canonical_id`. One of: `canonical`, `alias`.
    - `decision_id` (string, nullable): Identifier of a merge or reversal decision (`dec_<digits>`), a record you can cite.
    - `decided_at` (timestamp, nullable): A `Timestamp`, or `null` when unknown; the owning object says why.
  - `season_id` (object): How the requested identifier resolved. Present whenever the requested identifier is not the canonical one, and optional otherwise.
    - `requested_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `canonical_id` (string): OddsFinder identifier, `<prefix>_<digits>`, a per-kind sequence number without padding, leading zeros, grouping or sign (1 to 9223372036854775807). The prefix names the kind; the per-kind schemas fix it where a field or parameter has one kind. `Resolution` uses this generic form because its identifiers are of the resource's kind.
    - `status` (enum): `canonical`: the requested identifier is the identity itself; `alias`: it was retired by a merge decision and resolves to `canonical_id`. One of: `canonical`, `alias`.
    - `decision_id` (string, nullable): Identifier of a merge or reversal decision (`dec_<digits>`), a record you can cite.
    - `decided_at` (timestamp, nullable): A `Timestamp`, or `null` when unknown; the owning object says why.

Errors: `400` Malformed parameter or cursor (`invalid-request`).; `401` Missing or invalid credential (`unauthenticated`).; `403` Operation not permitted (`forbidden`) or restricted by grants/rights (`not-entitled`).; `422` Well-formed but unanswerable (`invalid-range`, `unsupported-historical-capability`).; `429` The per-minute rate limit is used up (`rate-limited`) or a daily allowance is exhausted (`quota-exceeded`). Failed requests (403, 404, other 4xx, 5xx) use up the per-minute rate limit too.; `500` Unexpected failure (`internal-error`); `request_id` identifies the server-side record.; `503` A service this operation depends on, or the access check, is temporarily unavailable (`unavailable`, `policy-unavailable`).

Example request (200 · Coaches):

```bash
curl -G https://api.example.com/v1/persons \
  -H "X-API-Key: $ODDSFINDER_API_KEY" \
  -d role=coach \
  -d valid_at=2026-10-01T00:00:00Z \
  -d known_at=2026-10-02T12:00:00Z
```

Example response (200):

```json
{
  "items": [
    {
      "id": "psn_1",
      "name": "Ada Kowalski",
      "name_status": "known",
      "full_name": null,
      "first_name": null,
      "last_name": null,
      "aliases": [],
      "association_code": "SYN",
      "born_on": "1978-03-14",
      "height_cm": null,
      "weight_kg": null,
      "birth_country_code": null,
      "position": null,
      "detailed_position": null,
      "preferred_foot": null,
      "birth_place": null,
      "contract_until": null,
      "roles": [
        {
          "role": "coach",
          "team_id": "tm_1",
          "competition_id": null,
          "from": "2026-07-01",
          "to": null
        }
      ],
      "knowledge": {
        "known_at": "2026-10-02T12:00:00Z",
        "as_requested": true
      },
      "sources": {
        "status": "withheld",
        "items": []
      }
    }
  ],
  "page": {
    "next_cursor": null,
    "limit": 50
  },
  "knowledge": {
    "known_at": "2026-10-02T12:00:00Z",
    "as_requested": true
  }
}
```
