# Policy receipts

`GET https://api.kapiworks.com/v1/acknowledgements`

The company's policy receipts in the order Kapi wrote them, each with the fields its hash covers, so anyone can check `receipt_sha256` and the chain without Kapi. Employees, partners and customers; a signed act carries its `signature_sha256`. Requires `acknowledgements:read`. Names and account emails also need `people:read`; without it they are left out.

Scope: `acknowledgements: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. Receipts written by then. Defaults to now. |
| `from` | string (date-time) or string (date) | No | Optional. Receipts written from this moment, inclusive; a date starts the company's day. At most 400 days before `as_at`. Omit it with a cursor, which 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. Part of the receipt hash. |
| `learning_space_id` | string (uuid) | Learning-space UUID. |
| `receipt_id` | string (uuid) | Receipt UUID. Part of the receipt hash. |
| `learner_profile_id` | string (uuid) | Person profile UUID; kept after erasure. Part of the receipt hash. |
| `person_name` | string or null | Name from the current profile, or the account email when it has none. Erased person once Kapi erased the person at the company’s instruction. |
| `account_email` | string or null | Email of the person’s Kapi account when this was read. Null for an erased person. |
| `door` | string | employee, partner or customer: the audience the person reached the policy through. |
| `signer_company` | string or null | The partner’s or customer’s company on the receipt, as the person signed. Null for employees, and once Kapi erased the person. |
| `course_id` | string (uuid) | Policy UUID. |
| `policy_title` | string | Policy title when the version was published. |
| `course_release_id` | string (uuid) | Published policy version UUID. Part of the receipt hash. |
| `version` | integer | Policy version number. |
| `effective_on` | string (date) | The version’s effective date, YYYY-MM-DD. |
| `version_digest` | string | The version digest: SHA-256 of these lines joined by line feeds: kapi.works.policy/2, course_id, version, document_sha256, statement_sha256, act, effective_on (empty when there is none), change_kind, renew_months, the doors sorted and joined with commas. |
| `act` | string | What the person did: acknowledged or signed. Part of the receipt hash. |
| `signed_at` | string | When Kapi wrote the receipt, in the exact form the receipt hash covers: YYYY-MM-DDTHH:MM:SS.ffffffZ, UTC. |
| `sign_in_methods` | string or null | How the session that signed had signed in, as Supabase Auth names the methods (such as password, totp or sso/saml), in the order it used them. |
| `assignment_id` | string (uuid) | Share UUID. Part of the receipt hash. |
| `cycle_id` | string (uuid) | The ask-again cycle: the receipt this one asks again after, or the all-zero UUID the first time. Part of the receipt hash. |
| `statement_sha256` | string | SHA-256 of the version’s statement, normalised: Unicode NFC, each run of white space as one space, trimmed. Part of the receipt hash. |
| `document_sha256` | string | SHA-256 of the version’s canonical HTML file. Part of the receipt hash. |
| `signature_sha256` | string or null | SHA-256 of the signature as text: the line typed and the words, or the line drawn and one line per stroke with its numbers joined by commas. Null for an acknowledgement. Part of the receipt hash. |
| `previous_sha256` | string | receipt_sha256 of the receipt Kapi wrote before this one for the company, whichever policy it was for; 64 zeros for the first. Part of the receipt hash. |
| `receipt_sha256` | string | The receipt hash: SHA-256 of these lines joined by line feeds: kapi.works.receipt/2, receipt_id, organization_id, course_release_id, learner_profile_id, assignment_id, cycle_id, act, statement_sha256, document_sha256, signature_sha256 (empty for an acknowledgement), signed_at, previous_sha256. |

## 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",
      "receipt_id": "2a9c7e5f-3b1d-4f8a-9e6c-4d2b0a8f6e44",
      "learner_profile_id": "1b3d5f7a-9c2e-4b6d-8f1a-3c5e7b9d2f55",
      "person_name": "Tomas Reyes",
      "account_email": "tomas.reyes@example.com",
      "door": "partner",
      "signer_company": "Northwind Logistics",
      "course_id": "3e1d5c7b-9a2f-4e6d-8c1b-5a7f9e3d1c22",
      "policy_title": "Partner code of conduct",
      "course_release_id": "6f4e2d1c-8b7a-4c9e-9d3f-2e1a0b9c8d33",
      "version": 2,
      "effective_on": "2026-11-01",
      "version_digest": "4b1d9e7f2a6c8e0b3d5f7a9c1e3b5d7f9a2c4e6b8d0f1a3c5e7b9d2f4a6c8e0b",
      "act": "signed",
      "signed_at": "2026-10-12T09:14:03.218734Z",
      "sign_in_methods": "password, totp",
      "assignment_id": "b6d4f2a8-9e1c-4a35-8f72-0e9d8c7b6a54",
      "cycle_id": "00000000-0000-0000-0000-000000000000",
      "statement_sha256": "7e9b1d3f5a7c9e2b4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c5e7b9d2f4a6c8e0b",
      "document_sha256": "0c2e4b6d8f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b5d7f9a2c4e",
      "signature_sha256": "9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c5e7b9d2f",
      "previous_sha256": "5a7c9e2b4d6f8a0c1e3b5d7f9a2c4e6b8d0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c",
      "receipt_sha256": "e3b5d7f9a2c4e6b8d0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b5"
    }
  ],
  "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.