---
title: "List Contract Term Events"
method: GET
path: "/contracts/{contract_id}/term-events"
tags: ["contracts"]
---

# List Contract Term Events

`GET /contracts/{contract_id}/term-events`

The contract's decision log — every record, undo and actioning.

One stream across the whole term chain rather than a route per term: it reads
as the contract's activity, with ``term_number`` marking the chapters.

Read-only, gated by router auth only, like ``/change-set``.

## Path parameters

- `contract_id` string, uuid, required

## Response `200`

Successful Response

- ContractTermEventResponse[]
  - `event_id` string, uuid, required
  - `term_id` string, uuid, required
  - `term_number` integer, required
  - `action` 'decision_recorded' | 'decision_cleared' | 'actioning_recorded' | 'actioning_undone', required — What happened on a term, for the append-only event log. The term carries only the *current* decision, so without this a correction is indistinguishable from never having decided. **The prefix names what the event happened to**, because the term records two facts that can each be taken back: the *decision* and the *actioning* of it. ``DECISION_CLEARED`` leaves the term with no decision; ``ACTIONING_UNDONE`` leaves the decision where it was and withdraws only the claim it was done.
  - `decision` 'renew' | 'renegotiate' | 'terminate' | 'replace' — What a user decided to do about a term coming up for renewal. A **fixed** set, not a per-company configurable one: it is what lets the email, the API and the state machine name the same thing without snapshotting a label onto every term. Two behavior pairs (RENEW/RENEGOTIATE, TERMINATE/REPLACE) — same effect, different record.
  - `decision_label` string, nullable
  - `decision_reason` string, nullable
  - `decision_source` 'user' | 'backfill' — Who recorded the decision. No ``SYSTEM_*`` member, deliberately: **nothing but a person records a decision**. A term that runs past its end date undecided stays ``OVERDUE`` and gets surfaced rather than auto-renewed on the customer's behalf — an invented decision is indistinguishable from one they made, and the renewal history is what customers audit.
  - `note` string, nullable
  - `actor` ContractTermEventActor — The user behind one decision event, shaped for the shared timeline avatar (``TaskUser`` client-side). Absent for a backfilled or system event, and for one whose user row has since gone.
    - `user_id` string, uuid, required
    - `first_name` string, required
    - `last_name` string, required
  - `actor_label` string, nullable
  - `acted_at` string, date-time, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/kobaltlabs/apis/fastapi.md) · [All operations](https://skmtc.dev/kobaltlabs/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/kobaltlabs/fastapi/revisions/425d5b8a3c17/schema)
