Renewals
One upcoming decision: a contract that's about to renew, and what you'll do about it.
A renewal represents one upcoming decision: a contract that’s about to renew, and what you’re going to do about it. Trimline opens a renewal 120 days before the contract’s term_end, or as soon as we find a contract that’s already inside that window.
Endpoints
- GET/v1/renewalsList renewals
- GET/v1/renewals/:idRetrieve a renewal
- POST/v1/renewals/:id/negotiateStart a negotiation
- POST/v1/renewals/:id/skipRenew as-is
The renewal object
{
"id": "ren_1Pq8sT2v",
"object": "renewal",
"vendor": { "id": "ven_9xKd02", "name": "Acme CRM" },
"contract": "ctr_4Lw7Yh",
"renews_on": "2027-02-01",
"notice_deadline": "2026-12-02",
"days_until_deadline": 23,
"status": "negotiating",
"current_annual_value": { "amount": 3840000, "currency": "usd" },
"proposed_annual_value": { "amount": 4108800, "currency": "usd" },
"estimated_savings": {
"low": { "amount": 384000, "currency": "usd" },
"high": { "amount": 960000, "currency": "usd" }
},
"best_offer": "off_6Tg2Ws",
"negotiation": "neg_8Hk2Pq",
"outcome": null,
"livemode": false
}
Statuses
| Status | Meaning |
|---|---|
upcoming | Opened, no decision yet. |
negotiating | A negotiation is in progress. |
awaiting_decision | An offer is on the table and needs your yes or no. |
accepted | You accepted new terms, and the order form is being signed. |
renewed | The contract renewed. outcome records on what terms. |
cancelled | Notice was given and the contract will end. |
skipped | You chose to renew as-is without negotiating. |
New statuses may be added. Treat unknown values as upcoming.
Other fields
proposed_annual_valuemoney, nullable | What the vendor plans to charge if nothing changes, including any uplift. |
estimated_savingsobject, nullable | Our estimated savings range, based on benchmarks for this vendor and your usage. It’s an estimate, not a promise. |
outcomeobject, nullable | Set once the renewal closes: the final annual value, term and a link to the savings record. |
List renewals
Sorted by notice_deadline, soonest first.
statusenum or list | For example status=upcoming or status[]=upcoming&status[]=negotiating. |
notice_deadline[lte]date | Deadlines on or before this date. |
vendorstring | Renewals for one vendor. |
Retrieve a renewal
Supports expand[]=negotiation and expand[]=contract.
Start negotiating
Opens a negotiation and generates the first draft to the vendor. Nothing is sent until the draft is approved.
target_annual_valuemoney | The price you’d be happy with. If you leave it out, we use the low end of estimated_savings. |
leversarray of enum | Any of price, seats, uplift, term, plan and payment_terms. The default is all of them. |
max_term_monthsinteger | The longest commitment you’ll accept. The default is 24. |
toneenum | friendly, neutral (the default) or firm. |
curl -X POST https://api.trimline.tech/v1/renewals/ren_1Pq8sT2v/negotiate \
-H "Authorization: Bearer $TRIMLINE_API_KEY" \
-H "Idempotency-Key: negotiate-ren_1Pq8sT2v" \
-H "Content-Type: application/json" \
-d '{
"target_annual_value": { "amount": 3000000, "currency": "usd" },
"levers": ["seats", "uplift", "term"],
"max_term_months": 24
}'
await fetch("https://api.trimline.tech/v1/renewals/ren_1Pq8sT2v/negotiate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRIMLINE_API_KEY}`,
"Idempotency-Key": "negotiate-ren_1Pq8sT2v",
"Content-Type": "application/json",
},
body: JSON.stringify({
target_annual_value: { amount: 3000000, currency: "usd" },
levers: ["seats", "uplift", "term"],
max_term_months: 24,
}),
});
Skip a renewal
Records that you’ve decided to renew on the current terms. We won’t contact the vendor, and no fee applies. Pass an optional reason string for your own records.
Something unclear or missing? Email developers@trimline.tech.