Lost Deals: what moves them on
Lost Deals: the reasons ranked, who owns them, and the call that re-opens one when its reason is answered.
A lost Deal keeps its reason. It re-opens as a new Deal when a shipped fix or Offer term answers that reason.
It moves on when
| To | When | The call | Event |
|---|---|---|---|
| A new Open Deal | a shipped change or Offer term answers its lost reason, and lead reactivation writes to them | POST /{namespace}/deals | Deal.created |
Who owns it
| Title | What it does here |
|---|---|
| AE | records the reason with POST /{namespace}/deals/{deal}/lose |
| SDR | re-opens it through lead reactivation, counted on Deals and trials opened |
How long it sits
| Deals | Window | Median days to get here | Stall line |
|---|---|---|---|
14 | 90 days | sales cycle, Not live yet, gaps #2 | none: it is a final Deal status |
| Lost reason, ranked | Deals | ARR lost | The Play that answers it |
|---|---|---|---|
price | 5 | −$5, | Risk-reversal offers |
no-decision | 3 | −$3, | Buying committee |
missing-capability | 2 | −$694 ARR | Lead reactivation |
timing | 2 | −$694 ARR | Lead nurture |
competitor | 1 | −$347 ARR | Switch kit |
no-fit | 1 | −$347 ARR | Positioning tournament |
The stall line is twice the median, read from each Deal’s statusSince · sample
The call that moves it
You, to your agent
Which lost deals can we re-open now? Re-open the one whose missing feature shipped, and record why the last one was lost.
curl "https://api.sb/leaseline.app/events?where=name%20%3D%20%22Deal.lost%22%20and%20at%20%3E%3D%20%222026-07-21%22&limit=14" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
curl -X POST "https://api.sb/leaseline.app/deals?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"organization":"organization_9","value":{"amount":348,"currency":"USD"},"nextStep":"Bulk renewals shipped Oct 9: show it to Cedar Grove on Oct 24"}'
# Not live yet (gaps #2)
curl -X POST "https://api.sb/leaseline.app/deals/deal_29/lose?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"Went with the tool their property manager already uses","lostReason":"competitor"}'import { $ } from 'startup-builder'
const { events } = await $.Event.list({ where: 'name = "Deal.lost" and at >= "2026-07-21"', limit: 14 }) // each with its free-text reason
const reopened = await $.Deal.create({ organization: 'organization_9', value: { amount: 348, currency: 'USD' }, nextStep: 'Bulk renewals shipped Oct 9: show it to Cedar Grove on Oct 24' }, { mode: 'try' }) // lead-reactivation re-opens a Deal once a shipped change answers its reason
return await $.Deal.lose({ deal: 'deal_29', reason: 'Went with the tool their property manager already uses', lostReason: 'competitor' }, { mode: 'try' }) // the typed reason beside the free text · Not live yet, gaps #2
npx startup-builder do Event.list --json '{"where":"name = \"Deal.lost\" and at >= \"2026-07-21\"","limit":14}'
npx startup-builder do Deal.create --json '{"organization":"organization_9","value":{"amount":348,"currency":"USD"},"nextStep":"Bulk renewals shipped Oct 9: show it to Cedar Grove on Oct 24"}' --try
npx startup-builder do Deal.lose --json '{"deal":"deal_29","reason":"Went with the tool their property manager already uses","lostReason":"competitor"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "const { events } = await $.Event.list({ where: 'name = \"Deal.lost\" and at >= \"2026-07-21\"', limit: 14 }) // each with its free-text reason\nconst reopened = await $.Deal.create({ organization: 'organization_9', value: { amount: 348, currency: 'USD' }, nextStep: 'Bulk renewals shipped Oct 9: show it to Cedar Grove on Oct 24' }, { mode: 'try' }) // lead-reactivation re-opens a Deal once a shipped change answers its reason\nreturn await $.Deal.lose({ deal: 'deal_29', reason: 'Went with the tool their property manager already uses', lostReason: 'competitor' }, { mode: 'try' }) // the typed reason beside the free text · Not live yet, gaps #2",
"mode": "try"
}
}Response200
application/json{
"deal": {
"$id": "https: //api.sb/ leaseline.app/ deals/ deal_29",
"$type": "Deal",
"status": "Lost",
"value": {
"amount": 348,
"currency": "USD"
},
"statusSince": "2026-10-19T11: 30: 00Z",
"lostReason": "competitor"
}
}
sample · 1 Not live yetPreviewWhen it won’t move
| Needs | Today | Mark |
|---|---|---|
| a typed lost reason beside the free text | POST /{namespace}/deals/{deal}/lose with a free-text reason | Not live yet, gaps #2 |
Plays that unstick it
| Play | What it does |
|---|---|
| Lead reactivation | Writes once to each old Lead nobody works, only when something new answers what they asked, from their last contact at the Startup. |
| Lead nurture | Follows up each unbought Lead with notes keyed to what they did, most in month one, until they buy, reply or go quiet 90 days. |
| Switch kit | Wins your rival’s users with an importer tested on its exports and a dry run they see first, stating no rival fact without a source. |
| Positioning tournament | Tests three ways of saying what you do, as ads that differ in one phrase, and counts only signups that fit and act. |
Compiled, not written: edit its page, then regenerate. Every step runs from a sentence or a line of code. In your words: the CRM words you know, and where each lives here.