Skip to content

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

ToWhenThe callEvent
A new Open Deala shipped change or Offer term answers its lost reason, and lead reactivation writes to themPOST /{namespace}/dealsDeal.created

Who owns it

TitleWhat it does here
AErecords the reason with POST /{namespace}/deals/{deal}/lose
SDRre-opens it through lead reactivation, counted on Deals and trials opened

How long it sits

DealsWindowMedian days to get hereStall line
1490 dayssales cycle, Not live yet, gaps #2none: it is a final Deal status
Lost reason, rankedDealsARR lostThe Play that answers it
price5−$5,827 ARRRisk-reversal offers
no-decision3−$3,087 ARRBuying committee
missing-capability2−$694 ARRLead reactivation
timing2−$694 ARRLead nurture
competitor1−$347 ARRSwitch kit
no-fit1−$347 ARRPositioning tournament

The stall line is twice the median, read from each Deal’s statusSince · sample

The call that moves it

Re-open a Lost DealMode try
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"
  }
}
Response200application/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 yetPreview

When it won’t move

NeedsTodayMark
a typed lost reason beside the free textPOST /{namespace}/deals/{deal}/lose with a free-text reasonNot live yet, gaps #2

Plays that unstick it

PlayWhat it does
Lead reactivationWrites once to each old Lead nobody works, only when something new answers what they asked, from their last contact at the Startup.
Lead nurtureFollows 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 kitWins 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 tournamentTests 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.

Contents