A finance director at a 200-person SaaS company walked me through the damage last quarter. Eighty-three vendor contracts, all tracked in one shared Google Sheet. Six of them auto-renewed before anyone noticed. Forty-seven thousand dollars in unplanned spend. Zero negotiation leverage for the next twelve months. One of those renewals was a data enrichment tool that exactly three people used.
This is the default state. According to Concord's contract management research[2], poor contract management leaks roughly 40% of contract value — actual figures vary by org size and portfolio complexity. For a company spending $1M to $3M annually on SaaS and infrastructure, that translates to hundreds of thousands of dollars hemorrhaging through missed credits, accepted price escalations, and renewals negotiated from zero leverage.
The radar is a structured agent pattern that monitors your contract master list continuously, extracts the dates and clauses that actually matter, and runs three parallel checks: renewal countdown, SLA drift detection, and supplier concentration risk. It turns a static document into a control surface.
Spreadsheets Are Tracking. They Are Not Enforcement.
The format is not the problem. The assumption that a human will check a static document on the right date is.
Every growing company starts the same way. Someone opens a Google Sheet. Columns for vendor name, annual cost, renewal date, owner. It works until contract number forty. Then it stops.
The failure mode is structural, not cosmetic. Notice periods range from 30 to 120 days. Auto-renewal clauses fire silently with price escalation already baked in — 20% annual increases are common and almost never challenged because nobody saw them coming. SLA credits have claim windows. Miss the window, the money you were owed evaporates. None of these mechanisms care whether your spreadsheet is up to date.
The real cost is not the line items. It is the negotiation leverage. Discover a contract renewed three days ago and you have zero leverage for twelve months. Discover it ninety days out and you have time to benchmark, evaluate alternatives, and negotiate from a position where the vendor knows you can walk. Same contract, two different worlds, separated by who saw the date first.
Manual updates that lag reality by weeks
One reminder date — usually the renewal itself, which is too late
Auto-renewal clauses invisible until they fire
SLA credits forfeit on a rolling claim-window expiry
Concentration risk hidden inside line-item budgets
Finance learns about the overrun after the invoice posts
Continuous parsing from contract source data, not memory
Tiered alerts at 90, 60, and 30 days, anchored on the notice deadline — not the renewal date
Auto-renewal clauses extracted, flagged, escalated before the window closes
SLA drift detected monthly, credit claims queued with deadlines attached
Concentration scored by category and operational function, not just spend
Finance gets actionable briefs before the renewal window opens
Three Checks. Each Catches a Failure the Others Miss.
Renewal countdown, SLA drift, and concentration risk run in parallel against the same parsed contract data.
The radar starts with a parser agent reading your master list — spreadsheet, Notion database, folder of PDF contracts, whatever you already have. It extracts structured fields: vendor name, contract start and end dates, notice period, auto-renewal clause, SLA commitments, service credit terms, annual contract value.
Three checks then run in parallel, every week:
Renewal Countdown scans for contracts entering the 90, 60, or 30-day windows before expiry. For each contract it computes the notice deadline — expiry date minus notice period — and flags contracts where the window is closing.
SLA Drift Detector compares vendor-reported uptime or performance against the SLA commitments extracted from each contract. When performance drops below threshold, it computes the credit owed and queues a claim with the claim-window deadline attached.
Concentration Risk Scorer aggregates spend by category and function. It flags categories where one vendor exceeds 60% of spend or capability, and identifies functions where a vendor disappearing tomorrow would take a system with it.
The Hard Part Is the Language, Not the Math
Lawyers get paid by the word. Auto-renewal clauses hide inside 'term and termination' paragraphs by design.
The countdown math is trivial. The parsing is not. Vendor contracts are written by lawyers paid by the word, and auto-renewal clauses live inside paragraphs about "term and termination" with phrasing like "unless either party provides written notice of non-renewal no fewer than sixty (60) days prior to the expiration of the then-current term."
The parser prompt has to handle this ambiguity directly — extract structured fields, attach a confidence score, escalate anything below threshold to human review. Below-threshold extractions never enter the alert pipeline unverified. A missed renewal caused by parser hallucination is worse than no automation at all:
contract-parser-prompt.yaml# Structured extraction prompt. Confidence below 0.7 escalates to human review.
system: |
Extract the following fields from vendor contracts. When language
is ambiguous, flag the ambiguity, attach a confidence score, and
return your best interpretation. Never silently default.
extraction_fields:
- name: renewal_date
description: "Contract end date or next renewal date"
format: "YYYY-MM-DD"
fallback: "Flag as UNKNOWN — escalate, never guess"
- name: notice_period_days
description: "Days before renewal that notice must be given"
format: integer
common_patterns:
- "no fewer than X days prior"
- "at least X days written notice"
- "X calendar days before expiration"
fallback: "Default to 90 days with LOW confidence — flag for review"
- name: auto_renewal
description: "Whether contract auto-renews"
values: ["yes", "no", "conditional"]
red_flags:
- "Price escalation on renewal (e.g., CPI adjustment)"
- "Renewal term longer than initial term"
- "Evergreen clause with no termination path"
- name: sla_commitments
description: "Uptime guarantees and performance thresholds"
format: "Array of {metric, threshold, credit_terms}"
- name: termination_for_convenience
description: "Whether early termination is allowed"
values: ["yes_with_fee", "yes_no_fee", "no"]Check 1: The Notice Deadline Is the Real Clock
Most trackers alert on the renewal date. By then the window has been closed for weeks.
Most contract trackers alert on the renewal date itself. That is the wrong date. With a 60-day notice period, an alert on the renewal date is two months late.
The countdown engine inverts this. The trigger date is the notice deadline — the last day you can act — and the alert timeline counts back from there. A contract renewing June 1 with a 60-day notice has a hard deadline of April 2. The 90-day alert fires January 2. The 60-day alert fires February 1. The 30-day alert fires March 3.
The content of each alert is different on purpose. The 90-day alert says: this is coming, start benchmarking alternatives. The 60-day says: decision needed this month, start the negotiation. The 30-day says: notice must go out within thirty days or this contract auto-renews on the vendor's terms.
| Alert Tier | Trigger | Required Action | Audience |
|---|---|---|---|
| 90-Day | 90 days before notice deadline | Begin benchmarking. Pull pricing from alternatives. Build leverage now, not later. | Procurement lead and budget owner |
| 60-Day | 60 days before notice deadline | Decide: renew, renegotiate, terminate. Start the negotiation if renewing. | Department head and finance |
| 30-Day | 30 days before notice deadline | Final action window. Submit non-renewal notice or confirm renewal terms in writing. | VP or C-level, plus legal |
| OVERDUE | Notice deadline passed | Contract auto-renews. Document the loss, adjust budget, schedule for next cycle. | Finance, for budget revision |
Check 2: Your Vendors Owe You Money You Have Not Asked For
SLA credits are a contractual right, not a favor. Half of orgs never claim them.
Most ops teams treat SLA credits as goodwill. They are not. They are a contractual obligation. When a cloud provider commits to 99.95% uptime and ships 99.8%, you are owed a credit — typically 10 to 25% of the monthly fee for that service, exact terms vary by contract. According to outage impact survey data[4], roughly half of organizations never file after serious outages. The money was already on the table. Nobody picked it up.
The drift detector runs monthly. It pulls uptime and performance data from your existing monitoring stack — Datadog, Grafana, CloudWatch, whatever — compares it against the SLA thresholds extracted from each contract, and generates a credit claim queue.
For a $500K cloud spend, unclaimed credits in the $15K to $30K range per year are plausible depending on vendor uptime and contract terms. That is not theoretical money. It is money already owed by contractual obligation, sitting unclaimed because nobody owns the claim process. The agent does not file claims automatically — that needs human sign-off — but it produces a prioritized queue with the vendor name, the SLA miss details, the credit amount owed, and the claim-window deadline. Filing becomes a five-minute task instead of a research project.
Check 3: One Vendor, 70% of a Capability — That Is a Dependency
Concentration risk does not appear on a line-item budget. It appears when you map vendors by function.
Concentration risk is invisible on a line-item budget. It surfaces only when you map vendors by function rather than by name. Thirty vendors looks like diversification. If one of them runs your authentication, your transactional email, and your logging pipeline, you have one dependency and a wishful spreadsheet.
The scorer categorizes each vendor by the functions they serve — authentication, payments, monitoring, communication, storage — and computes concentration percentages. Any category where one vendor exceeds 60% of spend or capability gets a review flag.
It also runs the disruption scenario explicitly: if this vendor disappears tomorrow, what breaks, how long until you migrate, what does emergency procurement cost. Uncomfortable questions. Cheaper to answer them now than in the middle of an incident.
One pattern that surfaces consistently when you actually do the mapping: the most dangerous concentration is rarely the highest-spend category. At a 120-person engineering org we mapped, the critical single point of failure was a $4,200/year log aggregation tool — not the $800K cloud contract everyone watched obsessively. Criticality does not scale with price. It scales with what breaks when the vendor is gone.
- [01]
Define a parseable contract schema
typescript// One source of truth. Confidence score travels with every record. interface VendorContract { vendorName: string; contractId: string; annualValue: number; startDate: string; // ISO 8601 endDate: string; noticePeriodDays: number; autoRenewal: 'yes' | 'no' | 'conditional'; priceEscalation?: string; slaCommitments: SLACommitment[]; functionalCategories: string[]; owner: string; confidenceScore: number; // 0-1, parser output, gates the alert pipeline } - [02]
Run the parser against existing documents and gate on confidence
bash# Parse every contract in the directory. Low-confidence records do not enter the pipeline. for contract in ./vendor-contracts/*.pdf; do bun run parse-contract "$contract" >> contracts.jsonl done # Below 0.7 confidence escalates to human review before alerts fire. bun run validate-contracts contracts.jsonl --min-confidence 0.7 - [03]
Schedule the three checks weekly
yaml# .github/workflows/contract-radar.yml # Three checks, one trigger, one brief. name: Contract Expiry Radar on: schedule: - cron: '0 8 * * 1' # Every Monday at 8am jobs: radar: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: bun run radar:renewal-countdown - run: bun run radar:sla-drift - run: bun run radar:concentration-risk - run: bun run radar:compile-brief - [04]
Compile and deliver the brief where decisions happen
typescript// Brief lands in Slack and email — wherever the owner already operates. const brief = await compileBrief({ renewals: renewalAlerts, slaDrift: slaFindings, concentration: concentrationFlags, }); await deliverBrief(brief, { channel: '#vendor-management', recipients: ['procurement@company.com'], format: 'structured', // RED / AMBER / GREEN sections, ranked by deadline });
Contract Expiry Radar — Go-Live Checklist
Full vendor contract inventory complete, including shadow IT and credit-card subscriptions
Parser run end-to-end, structured fields extracted, renewal dates and notice periods captured
Low-confidence extractions flagged and routed to human review before the alert pipeline accepts them
Monitoring integrations wired for SLA comparison — Datadog, CloudWatch, or equivalent
Functional categories defined for concentration scoring — by capability, not by vendor name
Alert tiers and delivery channels configured — Slack and email, ranked by deadline
Initial full scan complete, every CRITICAL finding reviewed and assigned
Weekly cron job scheduled and verified — first run lands a real brief
Named owner per vendor renewal conversation — not a Slack channel, a human
Quarterly recalibration cadence on the calendar — concentration scores drift between alerts
How do I handle contracts stored as scanned PDFs without OCR?
Run them through OCR before parsing. Tesseract handles clean scans. Degraded documents need a cloud OCR service — Google Document AI or AWS Textract. Drop the parser confidence score on every OCR'd document by default (0.5 is a reasonable floor) and require human review before any of those contracts enter the alert pipeline. A missed renewal caused by OCR garbling a date is worse than no automation. The audit trail must record which records came through OCR so failures are traceable to the right layer.
What if my vendor does not publish uptime data for SLA comparison?
Use your own monitoring as the source of truth. Synthetic monitoring — Pingdom, Uptime Robot, or your existing observability stack — pointed at the vendor's service endpoints generates timestamped availability records that are accepted as evidence in SLA credit disputes. Document the methodology: probe frequency, endpoint tested, threshold that counts as an outage. Store raw monitoring logs at minimum 90 days. Most credit windows are 30, but vendor disputes drag past that and the burden of proof sits with you.
How should I handle multi-year contracts with staggered renewal terms?
A 3-year contract is not one event. It is a sequence. Annual price-adjustment windows tied to CPI, SLA review dates, sometimes mid-term termination rights that expire after a specific month. Each one is an independent alert event with its own notice period. The 3-year renewal date is the last thing to watch. The Year 1 price adjustment window is usually the first — and the most expensive to miss, because silence accepts the escalation by default.
Is supplier concentration risk only about spend?
Spend is one axis. Operational dependency is the more dangerous one. A vendor at 3% of total spend can run a function — authentication, payment tokenization, transactional email — where an outage takes your product offline within hours. Score concentration on two dimensions, separately: spend share (financial exposure) and operational criticality (time-to-replace if the vendor disappears tomorrow). Low-spend, high-criticality vendors are the ones nobody monitors. They are also the ones most likely to fail without warning.
Operating Rules for the Radar
The radar informs. It does not act.
Termination notices and credit claims require human sign-off because they carry legal and relationship consequences. Automated notice-sending is a blast radius nobody volunteers to own.
Confidence below 0.7 escalates. It never silently enters the pipeline.
Ambiguous contract language is the failure mode that produces wrong alerts on the wrong date. Parser uncertainty is a feature when it gates the alert pipeline. It is a liability when it does not.
Master list updates within 48 hours of any new contract signing.
The radar is only as current as its source data. Stale inputs produce confident wrong answers — the worst class of failure for an alerting system.
Concentration scores reviewed quarterly, not just when alerts fire.
Concentration drifts between alerts. A category that was 40% one vendor six months ago is 65% today after a new product adoption. Drift is the default state of any system without an explicit owner.
- [1]Top IT Vendor Management Challenges in 2025 and How to Solve Them(technologymatch.com)↩
- [2]Contract Management Software: Ineffective Practices and Hidden Costs — Concord(concord.app)↩
- [3]Quarterly Vendor Contract Renewal Forecasting Checklist — Sirion(sirion.ai)↩
- [4]Reclaim SLA — SLA Credit Recovery Resource(reclaimsla.com)↩
- [5]SLA Enforcement: Making SaaS Providers Accountable for Downtime(jchanglaw.com)↩