---
title: "Get My Contracts"
method: GET
path: "/vrm/my-contracts"
tags: ["vrm"]
---

# Get My Contracts

`GET /vrm/my-contracts`

The current term of every contract in the caller's book of business.

The Contracts tab of the My Services landing: ``GET /contracts/current-terms``
narrowed to the vendors this user is assigned to and the services they are the
internal POC for (``_my_contracts_clause``) — the same book the Services tab
lists, built by the same ``build_current_term_rows``.

Ownership here is *access*, not the reminder-audience cascade
``?assigned_to_me`` resolves: Action Required answers "what do I owe?", this
answers "what am I responsible for?".

Read-only, gated by resource scope like the rest of this router.

## Response `200`

Successful Response

- ContractCurrentTermRowResponse[]
  - `contract_id` string, uuid, required
  - `contract_title` string, required
  - `contract_status` 'draft' | 'active' | 'expired' | 'terminated', required — ``DRAFT`` and ``TERMINATED`` are human judgments; the derivation in ``recompute_contract_status`` overwrites neither.
  - `vendor_id` string, uuid, nullable
  - `vendor_name` string, nullable
  - `vendor_website` string, nullable
  - `service_names` string[]
  - `term` ContractTermResponse — One term period, with the state and countdown derived server-side. ``state`` / ``status`` / ``decision_deadline`` / ``deadline_kind`` / ``days_remaining`` are computed, never stored — the table, the email, and this response all read them from the same helpers so they cannot disagree.
    - `term_id` string, uuid, required
    - `contract_id` string, uuid, required
    - `term_number` integer, required
    - `previous_term_id` string, uuid, nullable
    - `start_date` string, date, nullable
    - `end_date` string, date, nullable
    - `termination_notice_date` string, date, nullable
    - `notice_date_source` 'derived' | 'extracted' | 'manual' — Where a term's ``termination_notice_date`` came from. Drives whether moving ``end_date`` recomputes the notice date: only ``DERIVED`` dates are recomputed, so a human-entered or document-stated date is never silently overwritten.
    - `notice_period_value` integer, nullable
    - `notice_period_unit` 'days' | 'months' — Unit of a termination-notice period. Months are not 30 days: 3 months before 2026-05-31 is 2026-02-28, while 90 days before it is 2026-03-02. This generates a legal deadline, so the unit is stored rather than normalized to days (see ``backend.helpers.contract_terms.derive_notice_date``).
    - `renewal_term_months` integer, nullable
    - `auto_renews` boolean, nullable
    - `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.
    - `decided_by_user_id` string, uuid, nullable
    - `decided_by_label` string, nullable
    - `decided_at` string, date-time, nullable
    - `actioned_at` string, date-time, nullable
    - `actioned_by_user_id` string, uuid, nullable
    - `actioned_by_label` string, nullable
    - `state` 'open' | 'overdue' | 'decided' | 'renewed' | 'ended', required — A term's state, **derived** — never stored. Every value is a function of the dates and the decision, so a stored copy would have to be rewritten on each transition and would drift. The predicates live in ``backend.helpers.contract_terms.term_state``.
    - `status` 'overdue' | 'past_notice' | 'pending_decision' | 'pending_action' | 'active' | 'terminated' | 'replaced' | 'renewed' | 'renegotiated', required — Where a term stands, in the one phrase a surface shows for it. A different question from ``ContractTermState``, which is the state machine's own vocabulary. This one tells the **two lapsed dates apart** — a notice window that closed under a term still running is a different problem from a term that ran out entirely — and names outstanding work in the two halves somebody acts on. ``term_status`` derives it; nothing stores it. Declared **most urgent first**, and sorted on that order rather than on the labels, so ascending puts the work at the top of a list.
    - `decision_deadline` string, date, nullable
    - `deadline_kind` 'notice' | 'renewal' — Which of a term's two dates a reminder counts down to. A term has two real deadlines, not one derived deadline: the date you must give notice by, and the date the agreement turns over. Each gets its own ladder off its own cadence, because they are different distances from "act now" — a notice deadline wants months of warning, a renewal date wants days. Who receives a row is **not** encoded here: both configured audiences get every row, resolved at send time (``resolve_term_assignees``).
    - `days_remaining` integer, nullable
    - `in_effect` boolean
    - `attention_due` boolean
    - `notice_reminders_enabled` boolean
    - `renewal_reminders_enabled` boolean
    - `next_notice_reminder_date` string, date, nullable
    - `next_renewal_reminder_date` string, date, nullable
    - `notifications` ContractTermNotificationResponse[]
      - `notification_id` string, uuid, required
      - `lead_days` integer, required
      - `scheduled_for` string, date, required
      - `deadline_kind` 'notice' | 'renewal', required — Which of a term's two dates a reminder counts down to. A term has two real deadlines, not one derived deadline: the date you must give notice by, and the date the agreement turns over. Each gets its own ladder off its own cadence, because they are different distances from "act now" — a notice deadline wants months of warning, a renewal date wants days. Who receives a row is **not** encoded here: both configured audiences get every row, resolved at send time (``resolve_term_assignees``).
      - `target_date` string, date, required
      - `status` 'pending' | 'sent', required — Two values only: cancelling a reminder deletes the unsent row. ``AnnualKeyDates`` has three overlapping "off" states because it kept cancelled rows around. The audit of *why* reminders stopped lives on the term (``decided_at`` / ``decided_by_user_id``), not here.
      - `sent_at` string, date-time, nullable
    - `created` string, date-time, nullable
    - `modified` string, date-time, nullable

---

[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)
