# Training records at a moment

`GET https://api.kapiworks.com/v1/training-records`

Every record an employee owes at `as_at`, with its outcome then. Requires `training:read`. Names, work emails and certificate check codes also need `people:read`; without it they are left out.

Scope: `training:read`.

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `as_at` | string (date-time) or string (date) | No | RFC 3339 instant with an offset, or a date read as the end of the company's day. Defaults to now. |
| `course` | string (uuid) | No | Optional course UUID. The cursor keeps it. |
| `cursor` | string | No | Opaque next_cursor from the previous page. Send it unchanged to the same endpoint. It pins the snapshot and filters, and grants no access. |
| `limit` | integer | No | Rows per page, 1 to 200. Larger values are treated as 200. A page can hold fewer rows to stay within 3 MiB, so follow next_cursor until it is null. |

## Responses

| Status | Description |
| --- | --- |
| 200 | One page from a pinned company snapshot. |
| 400 | RFC 9457 problem details. Codes: invalid_request, invalid_cursor, key_in_url. Act on `code` or `type`; never parse `detail`. |
| 401 | RFC 9457 problem details. Codes: invalid_token. Act on `code` or `type`; never parse `detail`. |
| 403 | RFC 9457 problem details. Codes: insufficient_scope, ip_not_allowed. Act on `code` or `type`; never parse `detail`. |
| 404 | RFC 9457 problem details. Codes: not_found. Act on `code` or `type`; never parse `detail`. |
| 405 | RFC 9457 problem details. Codes: method_not_allowed. Act on `code` or `type`; never parse `detail`. |
| 422 | RFC 9457 problem details. Codes: before_history, record_too_large. Act on `code` or `type`; never parse `detail`. |
| 429 | RFC 9457 problem details. Codes: rate_limited, concurrent_limit. Act on `code` or `type`; never parse `detail`. |
| 502 | RFC 9457 problem details. Codes: read_failed. Act on `code` or `type`; never parse `detail`. |
| 503 | RFC 9457 problem details. Codes: unavailable, upstream_unavailable, writer_unavailable. Act on `code` or `type`; never parse `detail`. |
| 504 | RFC 9457 problem details. Codes: read_timeout. Act on `code` or `type`; never parse `detail`. |

## Fields of each row

| Field | Type | Meaning |
| --- | --- | --- |
| `deployment_id` | string (uuid) | Kapi deployment UUID. |
| `organization_id` | string (uuid) | Company UUID; the tenant boundary. |
| `learning_space_id` | string (uuid) | Learning-space UUID. |
| `sequence` | integer | Sequence of this stored row version in the company history; snapshot.sequence is the upper boundary for the pull. |
| `valid_from` | string (date-time) | When these facts took effect. |
| `recorded_at` | string (date-time) | When the history writer captured them. |
| `cause` | string | first, change or sweep. |
| `logic_version` | integer | Version of the shared owed-learning decider. |
| `record_id` | string (uuid) | Stable owed-record UUID: person, course and published release, or renewal cycle. |
| `learner_profile_id` | string (uuid) | Employee profile UUID; retained after erasure. |
| `person_name` | string or null | Name from its current source row. Erased person once Kapi erased the person at the company’s instruction. Certificate names are the issued subject name until then. |
| `work_email` | string or null | Address on the current source employee invitation; not the Auth account email. Null for an erased person. |
| `course_id` | string (uuid) | Course UUID. |
| `course_release_id` | string or null (uuid) | Immutable published course version UUID. |
| `renews_certificate_id` | string or null (uuid) | Certificate whose renewal created this owed record. |
| `requirement` | string | required, optional, no_longer_required or superseded. |
| `assigned_at` | string (date-time) | When the requirement began. |
| `due_at` | string or null (date-time) | Deadline instant, or null for no deadline. |
| `due_time_zone` | string | IANA company/deadline time zone. |
| `due_basis` | string | share_deadline, days_after_added, renewal, override or none. |
| `completed_at` | string or null (date-time) | Time Kapi’s server received the completion, including offline completions received later. |
| `completion_receipt_id` | string or null (uuid) | Server completion receipt UUID. |
| `ended_at` | string or null (date-time) | When the record stopped applying. |
| `ended_reason` | string or null | Fixed reason code, never typed text; source_removed when the person was erased. |
| `waived_at` | string or null (date-time) | When an administrator changed the obligation. |
| `waiver_actor_id` | string or null (uuid) | Administrator UUID. |
| `waiver_reason_code` | string or null | Fixed waiver reason code. |
| `outcome` | string | completed_on_time, completed_late, completed_before_requirement, not_due_yet, overdue, missed, excused, waived or optional_not_done. |
| `days_late` | integer or null | Ceiling of elapsed days past the deadline at completion or the end of the period/obligation. |
| `reminders_sent` | integer | Number of completed reminder sends known at the pinned capture. |
| `share_ids` | array of string (uuid) | JSON array of all contributing share UUIDs. |
| `doors` | array of string | JSON array of audience doors; includes employee. |
| `certificate_id` | string or null (uuid) | Certificate UUID. |
| `obligation_change_id` | integer or null | Source obligation-change ID. |

## Example response

```json
{
  "data": [
    {
      "deployment_id": "00000000-0000-4000-8000-000000000001",
      "organization_id": "4f6b2a52-1c1e-4f7a-9d3e-2b7c8a9e0d11",
      "learning_space_id": "8b2d6c3e-5f41-4a8e-9c27-1d0e3f4a5b62",
      "record_id": "a7e3c1b9-2d48-4f6a-8e15-9b0c7d6e5f43",
      "learner_profile_id": "c3a1e7f2-8d64-4b1f-a9e2-6f5d4c3b2a10",
      "person_name": "Amira Okafor",
      "work_email": "amira.okafor@example.com",
      "course_id": "d2f8b4a6-7c1e-4e93-b5a0-3c9e8f7d6a21",
      "course_release_id": "e5c2a9d7-4b3f-4c18-9a6e-2f1d0c9b8a77",
      "renews_certificate_id": null,
      "sequence": 1271,
      "valid_from": "2026-09-12T13:41:09Z",
      "recorded_at": "2026-09-12T13:41:12Z",
      "cause": "change",
      "logic_version": 4,
      "requirement": "required",
      "assigned_at": "2026-09-01T08:00:00Z",
      "due_at": "2026-09-30T22:59:59Z",
      "due_time_zone": "Europe/London",
      "due_basis": "share_deadline",
      "completed_at": "2026-09-12T13:41:09Z",
      "completion_receipt_id": "9c8b7a6f-5e4d-4c3b-8a29-1f0e9d8c7b66",
      "ended_at": null,
      "ended_reason": null,
      "waived_at": null,
      "waiver_actor_id": null,
      "waiver_reason_code": null,
      "outcome": "completed_on_time",
      "days_late": null,
      "reminders_sent": 1,
      "share_ids": [
        "b6d4f2a8-9e1c-4a35-8f72-0e9d8c7b6a54"
      ],
      "doors": [
        "employee"
      ],
      "certificate_id": "f1b9d3e5-6a2c-4d70-8b4e-5c3a2f1e0d98",
      "obligation_change_id": null
    }
  ],
  "total": 1,
  "snapshot": {
    "organization_id": "4f6b2a52-1c1e-4f7a-9d3e-2b7c8a9e0d11",
    "deployment_id": "00000000-0000-4000-8000-000000000001",
    "as_at": "2026-10-09T09:00:00Z",
    "from": null,
    "known_at": "2026-10-09T08:59:41Z",
    "sequence": 1284,
    "capture_sequence": 352,
    "chain_hash": "3f9a1c7e5b2d8f4a6c0e9b1d3f5a7c9e2b4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a",
    "logic": {
      "version": 4,
      "date": "2026-10-06"
    },
    "history_complete_from": "2026-10-06T05:00:00Z",
    "available": true
  },
  "next_cursor": null
}
```

The full contract, with every schema, is at https://api.kapiworks.com/v1/openapi.json.