{
  "topic": "audit",
  "path": [
    "audit"
  ],
  "title": "audit — entity audit event API",
  "synopsis": "The audit API exposes a per-entity event log covering entity lifecycle changes (`EntityChange` events) and workflow state-machine progression (`StateMachine` events). Events are returned newest-first and support cursor-based pagination.",
  "body": "# audit\n\n## NAME\n\naudit — entity audit event API: retrieve change and workflow audit events for a specific entity.\n\n## SYNOPSIS\n\n```\nGET  /api/audit/entity/{entityId}\nGET  /api/audit/entity/{entityId}/workflow/{transactionId}/finished\n```\n\nContext path prefix is `CYODA_CONTEXT_PATH` (default `/api`). All endpoints require `Authorization: Bearer <token>` except when `CYODA_IAM_MODE=mock`.\n\n## DESCRIPTION\n\nThe audit API exposes a per-entity event log covering entity lifecycle changes (`EntityChange` events) and workflow state-machine progression (`StateMachine` events). Events are returned newest-first and support cursor-based pagination.\n\nA third event type, `System`, is reserved for commercial backends. OSS backends never emit `System` events; the enum value is retained in the contract for wire compatibility with Cyoda Cloud.\n\n## ENDPOINTS\n\n**GET /api/audit/entity/{entityId}** — Search audit events for an entity\n\n- `entityId` (path): UUID — the entity to query\n\nQuery parameters (all optional):\n\n- `eventType`: multi-value filter. Accepted values: `StateMachine`, `EntityChange`, `System`. When omitted, defaults to all types except `System`. **`System` events are excluded from the default set. Including them may increase latency and load — use with caution.**\n- `severity`: `ERROR`, `INFO`, `WARN`, or `DEBUG`\n- `fromUtcTime`: RFC 3339 date-time — include events at or after this time (inclusive)\n- `toUtcTime`: RFC 3339 date-time — include events before this time (exclusive)\n- `transactionId`: UUID — filter to a single transaction\n- `cursor`: opaque string — pass `nextCursor` from the previous response to fetch the next page; omit for the first page\n- `limit`: string-encoded integer, 1–1000 (default 20; values above 1000 are clamped to 1000)\n\nResponse: `200 OK`, `application/json` — `EntityAuditEventsResponseDto`:\n\n```json\n{\n  \"pagination\": {\n    \"hasNext\": true,\n    \"nextCursor\": \"20\"\n  },\n  \"items\": [\n    {\n      \"auditEventType\": \"EntityChange\",\n      \"changeType\": \"UPDATE\",\n      \"severity\": \"INFO\",\n      \"utcTime\": \"2025-08-01T10:05:00.000000000Z\",\n      \"microsTime\": 1754042700000000,\n      \"entityId\": \"74807f00-ed0d-11ee-a357-ae468cd3ed16\",\n      \"transactionId\": \"9f1a2b3c-ed0e-11ee-a357-ae468cd3ed16\"\n    },\n    {\n      \"auditEventType\": \"StateMachine\",\n      \"eventType\": \"STATE_MACHINE_FINISH\",\n      \"severity\": \"INFO\",\n      \"utcTime\": \"2025-08-01T10:04:55.000000000Z\",\n      \"microsTime\": 1754042695000000,\n      \"entityId\": \"74807f00-ed0d-11ee-a357-ae468cd3ed16\",\n      \"state\": \"APPROVED\",\n      \"data\": {\"success\": true}\n    }\n  ]\n}\n```\n\n**EntityChangeAuditEventDto** fields (discriminated by `auditEventType: \"EntityChange\"`):\n\n- `changeType`: `\"CREATE\"`, `\"UPDATE\"`, or `\"DELETE\"` — the type of entity change\n- `changes`: before/after diff — **not yet emitted by the server (deferred gap)**; the field is declared in the OpenAPI schema but the server currently omits it from all responses. Do not rely on `changes` being present.\n- `severity`, `utcTime`, `microsTime`, `entityId`, `transactionId`, `actor` — plus `entityModel`, `consistencyTime`, `details`, `system` — inherited from `AuditEventDto` (see the `openapi` topic for the full schema)\n\n**StateMachineAuditEventDto** fields (discriminated by `auditEventType: \"StateMachine\"`):\n\n- `eventType`: one of `STATE_MACHINE_START`, `STATE_MACHINE_FINISH`, `CANCEL`, `FORCE_SUCCESS`, `WORKFLOW_FOUND`, `WORKFLOW_NOT_FOUND`, `WORKFLOW_SKIP`, `TRANSITION_MAKE`, `TRANSITION_NOT_FOUND`, `TRANSITION_NOT_MATCH_CRITERION`, `TRANSITION_ABORTED`, `PROCESS_NOT_MATCH_CRITERION`, `PAUSE_FOR_PROCESSING`, `STATE_PROCESS_RESULT`\n- `state`: entity state at the time of the event\n- `data`: optional event-specific payload (e.g. `{\"success\": true}` for `STATE_MACHINE_FINISH`; null for most event types). `TRANSITION_ABORTED` carries `{reason, transitionName, expectedTxId, actualTxId}`.\n\n**GET /api/audit/entity/{entityId}/workflow/{transactionId}/finished** — Get workflow finished event\n\nRetrieves the `STATE_MACHINE_FINISH` audit event for a specific entity and transaction. Provides direct access to the workflow outcome without scanning all audit events.\n\n- `entityId` (path): UUID\n- `transactionId` (path): UUID\n\nResponse: `200 OK`, `application/json` — `StateMachineAuditEventDto` (the finish event for the transaction).\n\nReturns `404` with `ProblemDetail` (`application/problem+json`) when the entity or finished event is not found.\n\n## ERRORS\n\n- `errors.ENTITY_NOT_FOUND` — `404` — entity does not exist, or no events found for the given entity/transaction\n- `errors.BAD_REQUEST` — `400` — `limit` parameter is not a valid integer or is less than 1\n\n## EXAMPLES\n\n**Fetch the 20 most recent audit events for an entity:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID\"\n```\n\n**Filter to EntityChange events only:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?eventType=EntityChange\"\n```\n\n**Filter to a specific transaction:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?transactionId=$TX_ID\"\n```\n\n**Paginate using a cursor:**\n\n```\nNEXT=$(curl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?limit=10\" \\\n  | jq -r '.pagination.nextCursor')\n\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?limit=10&cursor=$NEXT\"\n```\n\n**Get the workflow finished event for a transaction:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID/workflow/$TX_ID/finished\"\n```\n\n## SEE ALSO\n\n- crud\n- search\n- models\n- errors.ENTITY_NOT_FOUND\n- errors.BAD_REQUEST\n- openapi\n",
  "sections": [
    {
      "name": "NAME",
      "body": "audit — entity audit event API: retrieve change and workflow audit events for a specific entity."
    },
    {
      "name": "SYNOPSIS",
      "body": "```\nGET  /api/audit/entity/{entityId}\nGET  /api/audit/entity/{entityId}/workflow/{transactionId}/finished\n```\n\nContext path prefix is `CYODA_CONTEXT_PATH` (default `/api`). All endpoints require `Authorization: Bearer <token>` except when `CYODA_IAM_MODE=mock`."
    },
    {
      "name": "DESCRIPTION",
      "body": "The audit API exposes a per-entity event log covering entity lifecycle changes (`EntityChange` events) and workflow state-machine progression (`StateMachine` events). Events are returned newest-first and support cursor-based pagination.\n\nA third event type, `System`, is reserved for commercial backends. OSS backends never emit `System` events; the enum value is retained in the contract for wire compatibility with Cyoda Cloud."
    },
    {
      "name": "ENDPOINTS",
      "body": "**GET /api/audit/entity/{entityId}** — Search audit events for an entity\n\n- `entityId` (path): UUID — the entity to query\n\nQuery parameters (all optional):\n\n- `eventType`: multi-value filter. Accepted values: `StateMachine`, `EntityChange`, `System`. When omitted, defaults to all types except `System`. **`System` events are excluded from the default set. Including them may increase latency and load — use with caution.**\n- `severity`: `ERROR`, `INFO`, `WARN`, or `DEBUG`\n- `fromUtcTime`: RFC 3339 date-time — include events at or after this time (inclusive)\n- `toUtcTime`: RFC 3339 date-time — include events before this time (exclusive)\n- `transactionId`: UUID — filter to a single transaction\n- `cursor`: opaque string — pass `nextCursor` from the previous response to fetch the next page; omit for the first page\n- `limit`: string-encoded integer, 1–1000 (default 20; values above 1000 are clamped to 1000)\n\nResponse: `200 OK`, `application/json` — `EntityAuditEventsResponseDto`:\n\n```json\n{\n  \"pagination\": {\n    \"hasNext\": true,\n    \"nextCursor\": \"20\"\n  },\n  \"items\": [\n    {\n      \"auditEventType\": \"EntityChange\",\n      \"changeType\": \"UPDATE\",\n      \"severity\": \"INFO\",\n      \"utcTime\": \"2025-08-01T10:05:00.000000000Z\",\n      \"microsTime\": 1754042700000000,\n      \"entityId\": \"74807f00-ed0d-11ee-a357-ae468cd3ed16\",\n      \"transactionId\": \"9f1a2b3c-ed0e-11ee-a357-ae468cd3ed16\"\n    },\n    {\n      \"auditEventType\": \"StateMachine\",\n      \"eventType\": \"STATE_MACHINE_FINISH\",\n      \"severity\": \"INFO\",\n      \"utcTime\": \"2025-08-01T10:04:55.000000000Z\",\n      \"microsTime\": 1754042695000000,\n      \"entityId\": \"74807f00-ed0d-11ee-a357-ae468cd3ed16\",\n      \"state\": \"APPROVED\",\n      \"data\": {\"success\": true}\n    }\n  ]\n}\n```\n\n**EntityChangeAuditEventDto** fields (discriminated by `auditEventType: \"EntityChange\"`):\n\n- `changeType`: `\"CREATE\"`, `\"UPDATE\"`, or `\"DELETE\"` — the type of entity change\n- `changes`: before/after diff — **not yet emitted by the server (deferred gap)**; the field is declared in the OpenAPI schema but the server currently omits it from all responses. Do not rely on `changes` being present.\n- `severity`, `utcTime`, `microsTime`, `entityId`, `transactionId`, `actor` — plus `entityModel`, `consistencyTime`, `details`, `system` — inherited from `AuditEventDto` (see the `openapi` topic for the full schema)\n\n**StateMachineAuditEventDto** fields (discriminated by `auditEventType: \"StateMachine\"`):\n\n- `eventType`: one of `STATE_MACHINE_START`, `STATE_MACHINE_FINISH`, `CANCEL`, `FORCE_SUCCESS`, `WORKFLOW_FOUND`, `WORKFLOW_NOT_FOUND`, `WORKFLOW_SKIP`, `TRANSITION_MAKE`, `TRANSITION_NOT_FOUND`, `TRANSITION_NOT_MATCH_CRITERION`, `TRANSITION_ABORTED`, `PROCESS_NOT_MATCH_CRITERION`, `PAUSE_FOR_PROCESSING`, `STATE_PROCESS_RESULT`\n- `state`: entity state at the time of the event\n- `data`: optional event-specific payload (e.g. `{\"success\": true}` for `STATE_MACHINE_FINISH`; null for most event types). `TRANSITION_ABORTED` carries `{reason, transitionName, expectedTxId, actualTxId}`.\n\n**GET /api/audit/entity/{entityId}/workflow/{transactionId}/finished** — Get workflow finished event\n\nRetrieves the `STATE_MACHINE_FINISH` audit event for a specific entity and transaction. Provides direct access to the workflow outcome without scanning all audit events.\n\n- `entityId` (path): UUID\n- `transactionId` (path): UUID\n\nResponse: `200 OK`, `application/json` — `StateMachineAuditEventDto` (the finish event for the transaction).\n\nReturns `404` with `ProblemDetail` (`application/problem+json`) when the entity or finished event is not found."
    },
    {
      "name": "ERRORS",
      "body": "- `errors.ENTITY_NOT_FOUND` — `404` — entity does not exist, or no events found for the given entity/transaction\n- `errors.BAD_REQUEST` — `400` — `limit` parameter is not a valid integer or is less than 1"
    },
    {
      "name": "EXAMPLES",
      "body": "**Fetch the 20 most recent audit events for an entity:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID\"\n```\n\n**Filter to EntityChange events only:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?eventType=EntityChange\"\n```\n\n**Filter to a specific transaction:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?transactionId=$TX_ID\"\n```\n\n**Paginate using a cursor:**\n\n```\nNEXT=$(curl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?limit=10\" \\\n  | jq -r '.pagination.nextCursor')\n\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID?limit=10&cursor=$NEXT\"\n```\n\n**Get the workflow finished event for a transaction:**\n\n```\ncurl -s \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"http://localhost:8080/api/audit/entity/$ENTITY_ID/workflow/$TX_ID/finished\"\n```"
    },
    {
      "name": "SEE ALSO",
      "body": "- crud\n- search\n- models\n- errors.ENTITY_NOT_FOUND\n- errors.BAD_REQUEST\n- openapi"
    }
  ],
  "see_also": [
    "crud",
    "search",
    "models",
    "errors.ENTITY_NOT_FOUND",
    "errors.BAD_REQUEST",
    "openapi"
  ],
  "stability": "stable",
  "actions": []
}
