Skip to content

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.

Channel
Lists
Run oneMode try
You, to your agent

Hand our latest reason match to the SDR agent and show me what it chose and why. Don’t send.

curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Visitor.identified%22%2C%20%22Lead.nurtured%22%2C%20%22Gathering.registered%22%2C%20%22Offer.trialed%22%2C%20%22Contact.imported%22%2C%20%22Version.deployed%22%2C%20%22Content.published%22%2C%20%22Offer.published%22%2C%20%22Gathering.opened%22%2C%20%22Opening.published%22%2C%20%22Company.funded%22%2C%20%22Conversation.answered%22)&limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# Not live yet (gaps #7)
curl -X POST "https://api.sb/leaseline.app/triggers/fire?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"like":"event_1214"}'

# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22lead_73%22" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/actions?where=on%20%3D%20%22lead_73%22" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
import { $ } from 'startup-builder'

const { events: [last] } = await $.Event.list({ where: 'name in ("Visitor.identified", "Lead.nurtured", "Gathering.registered", "Offer.trialed", "Contact.imported", "Version.deployed", "Content.published", "Offer.published", "Gathering.opened", "Opening.published", "Company.funded", "Conversation.answered")', limit: 1 })   // { play } compiled to this Play’s Trigger Events
const { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' })   // the same Event again, in try mode · Not live yet, gaps #7
const { decisions: [decision] } = await $.Decision.list({ where: `on = "${subject}"` })   // what it chose, and why · Not live yet, gaps #7
const { actions } = await $.Action.list({ where: `on = "${subject}"` })   // what it did, with its checks · Not live yet, gaps #7
return { decision, actions }
npx startup-builder do Event.list --json '{"where":"name in (\"Visitor.identified\", \"Lead.nurtured\", \"Gathering.registered\", \"Offer.trialed\", \"Contact.imported\", \"Version.deployed\", \"Content.published\", \"Offer.published\", \"Gathering.opened\", \"Opening.published\", \"Company.funded\", \"Conversation.answered\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1214"}' --try   # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"lead_73\""}'   # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"lead_73\""}'   # Not live yet (gaps #7)
{
  "name": "do",
  "arguments": {
    "code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Visitor.identified\", \"Lead.nurtured\", \"Gathering.registered\", \"Offer.trialed\", \"Contact.imported\", \"Version.deployed\", \"Content.published\", \"Offer.published\", \"Gathering.opened\", \"Opening.published\", \"Company.funded\", \"Conversation.answered\")', limit: 1 })   // { play } compiled to this Play’s Trigger Events\nconst { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' })   // the same Event again, in try mode · Not live yet, gaps #7\nconst { decisions: [decision] } = await $.Decision.list({ where: `on = \"${subject}\"` })   // what it chose, and why · Not live yet, gaps #7\nconst { actions } = await $.Action.list({ where: `on = \"${subject}\"` })   // what it did, with its checks · Not live yet, gaps #7\nreturn { decision, actions }",
    "mode": "try"
  }
}
Response200application/json
{
  "decision": {
    "$id": "https://api.sb/leaseline.app/decisions/decision_440",
    "$type": "Decision",
    "choice": "own-the-miss",
    "reason": "Teo Marsh at Granite Row asked on Mar 3 whether Leaseline handles a second owner and nobody answered; per-owner batches shipped Sep 28 (the changelog)",
    "stakes": "low",
    "options": [
      "send-the-reason",
      "own-the-miss",
      "founder-writes-it",
      "to-the-ae",
      "park-it",
      "release-it"
  …
sample · 4 Not live yetPreview

On PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim

action_1 checked Teo’s address is still live. action_2 is the one Message, held to his 09:00 and signed by the labeled agent, since nobody at Leaseline wrote to him before.

+6.6 per 100 delivered · ■■□□ Early sign · n 218 · path → arr

Try another: the recordChoiceReason
Granite Row: a Form on Mar 3, never answered; per-owner batches shipped Sep 28own-the-missthe answer is now published
Brookside Flats: a lapsed trial; said “Team is too pricey for 60 units”send-the-reasonTeam’s new 60-unit price answers the blocker
Linden Court: a held Meeting in April, then silencefounder-writes-itfirst tier: you write it
Ashgrove Homes: a registrant with no new reason since Maypark-itno fresh reason; re-matched every Monday

Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Reactivated pipeline → Deals and trials opened → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +6.6 Deals or trials opened per 100 delivered × 120 delivered a month × 0.25 opens to paid × $590 first order ARR ≈ +$1,168. Under First signal: About 9 weeks to tell a +6.6 lift at 120 delivered a month with 1 in 10 held back (8 to read, 1 to mature); at 56 days it reads Early sign.

sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Version.deployed · first reason match 52m · 8 keys Not live yet

Start it this week

Terminal
npx startup-builder add play lead-reactivation   # 1 · writes plays/lead-reactivation.mdx (Not live yet, gaps #5)

# 2 · dry run; below, its 422 on 2026-08-24
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"lead-reactivation"}'

# 3 · keep it, at You approve each one for the first 50 drafts
curl -X POST https://api.sb/leaseline.app/campaigns \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"lead-reactivation"}'

# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/lead-reactivation \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endsAt":null}'

# off: no round sends; parked records keep their reasons
curl -X PATCH https://api.sb/leaseline.app/campaigns/lead-reactivation \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endsAt":"now"}'
422Refusedlead-reactivation can’t start: 2 checks fail and 1 warns.
CheckFixThen
use-when pass · Not live yet, gaps #8612 owned records no Play works, quiet 90 days or morePOST /{namespace}/metrics/query
baseline pass · Not live yet, gaps #80.9 Deals or trials opened per 100 quiet records a month, with no Message, n 612POST /{namespace}/metrics/query
collection-record failMap each imported row to the Form, Registration or trial that collected it.Contact.import
mailbox-warm fail · Not live yet, gaps #1Finish warming the reactivation Mailbox, about 5 more days.POST /{namespace}/mailboxes/{mailbox}/warm
domain-authenticated pass—POST /{namespace}/domains/{domain}/authenticate
role-unstaffed warn · Not live yet, gaps #8Staff the AE, or leave it: Interested replies come to you.POST /{namespace}/roles/{role}/staff
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "lead-reactivation can’t start: 2 checks fail and 1 warns.",
  "checks": [
    {
      "check": "use-when",
      "status": "pass",
      "observed": "612 owned records no Play works, quiet 90 days or more",
      "doc": "/plays/lead-reactivation#check-use-when",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "pass",
      "observed": "0.9 Deals or trials opened per 100 quiet records a month, with no Message, n 612",
      "doc": "/plays/lead-reactivation#check-baseline",
      "then": "Metric.query"
    },
    {
      "check": "collection-record",
      "status": "fail",
      "observed": "40 of 300 imported rows",
      "doc": "/plays/lead-reactivation#check-collection-record",
      "fix": "Map each imported row to the Form, Registration or trial that collected it.",
      "then": "Contact.import"
    },
    {
      "check": "mailbox-warm",
      "status": "fail",
      "observed": "day 9 of 14",
      "doc": "/plays/lead-reactivation#check-mailbox-warm",
      "fix": "Finish warming the reactivation Mailbox, about 5 more days.",
      "then": "Mailbox.warm"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "doc": "/plays/lead-reactivation#check-domain-authenticated",
      "then": "Domain.authenticate"
    },
    {
      "check": "role-unstaffed",
      "status": "warn",
      "roles": [
        "sales-lead"
      ],
      "owned": 9,
      "doc": "/plays/lead-reactivation#check-role-unstaffed",
      "fix": "Staff the AE, or leave it: Interested replies come to you.",
      "then": "Role.staff"
    }
  ]
}

It says no, says why, and names the fix.

CheckFix (one call)Your timeWait
use-when · baseline · pass: 612 quiet records; 0.9 per 100 a month, n 612 (gaps #8)POST /{namespace}/metrics/query on reactivated-pipeline, which fills Before in Your number1 minnone
collection-record · fail (gaps #8): 40 of 300 imported rowsContact.import (Not live yet, gaps #2) again with each row’s collecting Form, Registration or trial; rows without one are refused20 minnone
mailbox-warm · fail: day 9 of 14POST /{namespace}/mailboxes/{mailbox}/warm on the reactivation Mailbox0 minabout 5 days
domain-authenticated · role-unstaffed · pass; warn (gaps #8): 9 of your records have a person owner, youPOST /{namespace}/roles/{role}/staff, or leave it: Interested replies come to you, and the agent drafts into your queue for your 90 minnone

Your number · Before 0.9 per 100 with no Message · Now 6.6 per 100 delivered · Target 8 by Dec 31 · ■■□□ Early sign · n 218 matured

Each drafted Message costs about $0.05 (Worker cost), address checks cost $0.01 each, and sending runs on the shared broadcast stream. A founder note costs your 3 minutes. That comes to about $7 a month at 120 delivered, plus a one-time $3 to check the 300 imported addresses.

When it starts

WhenTrigger idStarts onWindowHow it gets in
A Change reaches every Customer and answers a need someone in the pool statedneed-shippedevent on Version.deployed where answers a need a pooled Person stated30dfrom launch-week’s feed of shipped Changes
An Offer changes its price, term or plan size, answering a stated blockeroffer-changedevent on Offer.published where answers a blocker a pooled Person stated30dPOST /{namespace}/offers/{offer}/publish
A Form Lead is 30 days old with no reply, no Enrollment and no Dealform-ghostedstate on Visitor.identified where made by a Form, 30 days old, no Worker reply, no Enrollment and no Deal730dfrom your Forms, through POST /{namespace}/leads
+ 13 more for nurture exits, silent registrants, lapsed trials, imports, owed answers, Gatherings, outcome facts, hiring, funding, not-now dates, known returns and resolved loss reasons (?lanes=all)
One signed delivery · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1214",
  "$type": "Event",
  "name": "Version.deployed",
  "at": "2026-10-19T07:30:20Z",
  "seq": 1214,
  "data": {
    "change": "changes/change_33",
    "title": "Per-owner renewal batches",
    "rollout": 1,
    "matches": [
      {
        "lead": "leads/lead_73",
        "said": "Do you handle a second owner on one portfolio?",
        "saidAt": "2026-03-03",
        "answered": false
      }
    ]
  }
}
Reproduce it in test
# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":"Version.deployed","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Version.deployed --like event_1214   # replays the delivery through reason matching
npx startup-builder clock advance --by 7d   # closes the round after 7 silent days

Who runs it

SDR · your agent (role:prospector, worker_2) holds the Key Result: it pools, dedupes and matches each record to one reason, and sends as the Person’s last correspondent or as the labeled agent. First-tier records hand to you (Dana Okafor, person, worker_1), and Interested replies go to AE · Priya Shah (person) (role:sales-lead, worker_3, staffed on day 9).

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Send the reason · Own the missIt does it, you can stop it50 drafts reviewed, 46 passedmet on day 16 (50 drafts)a wrong-match or negative-reply Stop → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Founder writes itYou approve each one14 notes, all yoursnever: a note in your name stays yours—POST /{namespace}/tasks/{task}/return with a reason
To the AE · Not now · Let them goIt does it9 of 9 · 211 parked · 64 released—a customer-collision → You approve each one, plus an ownership checkPOST /{namespace}/actions/{action}/redirect
Change the match ruleYou approve each one1 merged of 1never—POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert
Never: a check-in with no reason, a Visit or Page view in the body, a reply prefix that implies a threadRefused, every time3 drafted, 3 refusednever—the watched-event Check and the critic pass

What it reads · What it may call. It reads what each Person did with Leaseline and said, with dates, and only public sources for a reason; a return to the site may raise a record’s rank but never appears in what it writes. It may call POST /{namespace}/contacts/{contact}/enrich, POST /{namespace}/messages/{message}/schedule and POST /{namespace}/leads/{lead}/assign. Its tools are POST /{namespace}/messages/{message}/schedule, POST /{namespace}/tasks/{task}/assign, POST /{namespace}/meetings/book, and any other call becomes an Approval under the Role’s Mandate.

The brief (folded): compiled Agent-register Markdown · play:lead-reactivation@1 · each line names its record key
You hold the SDR Key Result: 8 Deals or trials opened per 100 delivered by 2026-12-31. ← worker, metric
On each reason Event, match a record and choose one option, or write NO_REASON.  ← triggers, chooses
Match by reason code first, then by model at 0.8 or more; under that, park it.   ← your file, line 4
State only what they did with Leaseline, with its date, and a reason with its public source. ← copyRules 2, 3
Never name a Visit, an open, a click or a return to the site.                    ← copyRules 4, watched-event
One round per reason kind; never repeat an Offer, fact or reason to a Person.    ← copyRules 11

The slow loop, as a Change. decision_398 (2026-09-21, weekly) read 4 positive replies from 31 model matches at 0.7 to 0.8 against 11 from 62 at 0.8 or more, with 3 wrong matches in the lower band, so change_31 raised the model match line from 0.7 to 0.8 (your file, line 4), and Dana merged it with POST /{namespace}/changes/{change}/merge. Replayed on past matches, POST /{namespace}/changes/{change}/review cut wrong matches to 0 of 40; read back at +21d it is 1 of 37, n 37, ■□□□ Too early to tell (Example, day 49).

Bring your own agent (folded) sends at It does it, you can stop it when it matches or beats the seated agent on the eval suite, and at You approve each one when it does not; POST /{namespace}/roles/{role}/staff seats it.

Terminal
npx startup-builder eval --scenario lead-reactivation-251 --agent "claude -p" --seat prospector   # seated: 6.6 per 100, 0 watched Events sent, 0 repeats, $0.06 a delivered · yours: 5.9, 1 watched Event drafted, 0 repeats, $0.08 → You approve each one

What it can do next

OptionPicked whenDecided byRunsHands toIf it’s just you
Send the reason send-the-reasona fresh announced reason with a public source answers what they statedAgent’s call, with its reasonreactivation-round: one Message, then the round closes after 7 silent daysnobody; replies go through the reply matrixthe same
Own the miss own-the-missa Form nobody answered, and the answer is now publishedYour rule (the ghosted-Form template)reactivation-round with the miss owned in one clause → POST /{namespace}/messages/{message}/schedulenobodythe same
Founder writes it founder-writes-itfirst tier: a held Meeting or a thread with a personYour rule (the tiers)reactivation-round-founder in their last thread, or reactivation-tray-founder on LinkedIn → POST /{namespace}/tasks/{task}/assignyou write it, due 1 business day · Take this oneyou
To the AE to-the-aean Interested reply, or a question only a person can answerAgent’s call, with its reasonPOST /{namespace}/meetings/book with the AE’s times → POST /{namespace}/tasks/{task}/assignPOST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 60 min (response-60m), Brief attached · Take this oneyou, within 60 min
Not now park-itno fresh reason, or every reason kind already used with themYour rule (line 4)nothing; parked and re-matched every Mondaynobodythe same
Let them go release-itan active Customer or open Deal at their Organization, a lost Deal, or another Play holds themYour rule (one Play per record)nothing; names the Play or the owner that holds themthe holderthe same
When they write backFixture replyWhat happensWho answersBy whenCall
Interested“Yes, this is what we needed. Can we talk Thursday?”To the AE: three times from Priya’s calendar; the round closesAE · Priya Shah (person)60 minPOST /{namespace}/meetings/book
Send me pricing“What does it cost for 64 units?”answers with the Pricing Page’s list Price and one next stepSDR · your agent5 minPOST /{namespace}/conversations/{conversation}/answer
Not now“Not this year.”no round for 12 months; a date they name becomes a not-now-dateSDR · your agentat oncePOST /{namespace}/messages/{message}/schedule
Wrong person“I left Granite Row in June.”thanks them; the record closes, and it never writes to an address from their textSDR · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Oct 28the round waits for the return date and closes 7 days afternobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answer“Can you move our 4 years of history over?”To the AE, the question in the BriefAE · Priya Shah, or you60 minPOST /{namespace}/conversations/{conversation}/escalate
Stop“Remove me.”a Suppression on every scope; nothing sends again, from any of your Startupsnobodyat oncePOST /{namespace}/contacts/{contact}/suppress

When it hands to you

First-tier records go to you (Dana Okafor, person) to write; Interested replies go to AE · Priya Shah (person), and before day 9 they came to you. As captured, one Brief per Role (brief is Not live yet, gaps #7).

What lands in each queue · sample
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_530",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-20T17:00:00Z",
    "on": "lead_79",
    "brief": {
      "who": "Linden Court, 88 units; you held a Meeting on 2026-04-14",
      "said": "we’ll revisit once owners can see their own renewals",
      "reason": "the owner portal shipped 2026-10-18 (change_41)",
      "chose": "founder-writes-it",
      "thread": "your April thread",
      "never": [
        "a check-in with no reason",
        "a Visit in the body"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_486",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-10-07T15:10:00Z",
    "on": "lead_47",
    "brief": {
      "who": "Brookside Flats, 60 units, a lapsed trial",
      "said": "Yes, the 60-unit price works. Can we talk Thursday?",
      "chose": "to-the-ae",
      "why": "an Interested reply",
      "never": [
        "a discount beyond the Pricing Page"
      ]
    }
  }
]

You answer a first-tier brief by writing the note in their last thread, with POST /{namespace}/tasks/{task}/return and a reason, or with POST /{namespace}/actions/{action}/redirect. The AE answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect; once claimed, the agent’s pending sends to that Person cancel with claimedByPerson (Not live yet, gaps #7). A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate (AE to you), and unanswered-positive fires.

On time: AE · Priya Shah: 8 of 9 claimed within 60 min, median 24 min, n 9 (the 9th waited 78 min and paused new sends). You: 14 of 14 notes within 1 business day, n 14, ■■□□ Early sign beside Other Startups’ 90 %. Your queue: counted by kind: in week 1, 50 draft reviews and 6 founder briefs; after day 16, about 2 founder briefs and 1 AE hand-off a week.

The fixed line: POST /{namespace}/deals/{deal}/assign sets owner to the receiving person, the agent is never a Deal’s owner, and Meetings land on the owner’s calendar under the owner’s name.

When it won’t send

Check (refuses one send)RefusesFixThen
owned-by-a-person (rule j; Not live yet, gaps #8)a round to a Contact whose Lead or open Deal a person owns, or whose Conversation a person claimedLeave it to the person who owns it: the draft waits in their queue.POST /{namespace}/tasks/{task}/assign
customer-collision (gaps #1; one sent pauses the Play)a round to a Person at an Organization with an active Subscription or an open DealSend it to their CSM or AE instead.POST /{namespace}/conversations/{conversation}/assign
approved-pages (Not live yet)a fact, price or outcome that the claims source and the Person’s own record lackCut the line, or publish the Page that says it.POST /{namespace}/sites/{site}/publish
watched-event (copy rule 4)a Visit, an open, a click, a resolved Organization or a return to the site in the bodyCut it; lead with the reason and its public source.POST /{namespace}/content/draft
verification (email)a List whose address check finds over 20 % invalidReview the List; send to the verified addresses only.POST /{namespace}/tasks/next
market-holda draft to an unresolved Market or an unverified rowResolve the Market; the draft waits and never retries another way.POST /{namespace}/tasks/next
Stop (pauses the Play)Pauses whenThen
bounce (email)hard bounces over 2 % of a day’s sends, at 50 or morethe stream pauses and its queue is checked again
complaint (email)stop and hostile replies over 0.3 % of the last 1,000 on the broadcast stream, hostile counted 5 timesthe stream pauses
outbound-complaint (email)the same weighting over 1 % of an outbound Domain’s last 1,000the Domain pauses
provider-spam (email)a mailbox provider reports 0.08 % spamevery Mailbox of the Play pauses on that provider
repeat-complaint (email)2 complaints in 7 days from People written to beforeevery send pauses until you review a dedupe audit of the last 200
wrong-matchthe monthly hand check finds over 10 % of 30 reasons miss the stated needmatching halts
reply-floor (email)positive replies under 2 % after 200 deliveredthe List stops
negative-reply (email)stop and hostile replies over 3 % of delivered, after 100the List pauses
unanswered-positive (standard response-60m)an Interested reply waits past its due timenew sends pause; POST /{namespace}/tasks/{task}/claim resumes it
freshnessa failed Monday canary, or 14 days with no reason Event while Changes shippedmatching pauses
kill-switchyou press itevery Tactic pauses on every stream at once

The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Granite Row thread in Example.

422RefusedThe round to Granite Row did not send: it names a return to the site.
CheckFixThen
watched-event failCut it; lead with the reason and its public source.POST /{namespace}/content/draft
customer-collision pass · Not live yet, gaps #1—POST /{namespace}/leads/{lead}/assign
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The round to Granite Row did not send: it names a return to the site.",
  "checks": [
    {
      "check": "watched-event",
      "status": "fail",
      "doc": "/plays/lead-reactivation#check-watched-event",
      "fix": "Cut it; lead with the reason and its public source.",
      "then": "Content.draft"
    },
    {
      "check": "customer-collision",
      "status": "pass"
    }
  ]
}

It says no, says why, and names the fix.

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "reason": {
      "limit": "unanswered-positive",
      "observed": "78m",
      "bound": "60m",
      "window": "1 reply"
    },
    "doc": "/plays/lead-reactivation#stop-unanswered-positive",
    "task": "task_489"
  }
]

Did it work

Both halves are read from the same random assignment, 1 in 10 newly eligible records per List held back for 60 days (rules m–o), and each figure’s call is POST /{namespace}/metrics/query by node and by arm; every node above the leaf is Not live yet (gaps #4).

+6.6 per 100 delivered · ■■□□ Early sign · n 218 · path → arr

Chose
own-the-miss
Why
Teo Marsh at Granite Row asked on Mar 3 whether Leaseline handles a second owner and nobody answered; per-owner batches shipped Sep 28 (the changelog)
From
send-the-reason · own-the-miss · founder-writes-it · to-the-ae · park-it · release-it
Expects
a Deal or trial opened within 30d
Reopens when
no Lead.convert or Offer.trialed for lead_73 within 30d
By
worker_2
JSON
{
  "$id": "decisions/decision_440",
  "$type": "Decision",
  "choice": "own-the-miss",
  "reason": "Teo Marsh at Granite Row asked on Mar 3 whether Leaseline handles a second owner and nobody answered; per-owner batches shipped Sep 28 (the changelog)",
  "stakes": "low",
  "options": [
    "send-the-reason",
    "own-the-miss",
    "founder-writes-it",
    "to-the-ae",
    "park-it",
    "release-it"
  ],
  "by": "worker_2",
  "on": "lead_73",
  "expected": "a Deal or trial opened within 30d",
  "reopensWhen": "no Lead.convert or Offer.trialed for lead_73 within 30d"
}
NodeAgent half (delivered)Held backAddedConfidenceBasis
reactivated-pipeline6.6 per 100 (13 of 196 matured)0 (0 of 22)+6.6 [0.4, 12.8]■■□□ Early signheld back at random · n 218 · 33 still maturing
opened-deals-and-trials13 Deals and trials opened0+13, carried: the leaf counts this node’s units■■□□ Early signthe same assignment
new-arr ↑$4,375, 5 Customers (3 on Pro, 1 on Team, 1 on the $2,400 plan) · Booked: credited, not all caused by this Play$0+$2,232 per 100 delivered [−$800, +$5,300] · Worth about +$1,200 a month■□□□ Too early to tell (5 vs 0 Customers)the same · 4 trials still deciding
net-new-arr · arr+$4,375$0carried: it moves no other bridge term■□□□ Too early to tellcarried from new-arr

The leaf counts Deals or trials opened within 30 days per 100 Persons delivered one Message, against the held-back half, where a self-serve first paid Order counts as one, to 200 matured in each half; at 196 and 22 so far the held-back half runs on.

How it moves it: each Message cites one shipped Change, Offer or published answer that matches what the Person said, with its public source, from their last correspondent.

Guardrails: treated against held back: outside-paying-customers, 5 against 0, and stops plus hostile replies, 1.4 % of delivered against the 3 % Stop; 0 repeat complaints.

The Campaign card · sample
{
  "$id": "https://api.sb/leaseline.app/campaigns/lead-reactivation",
  "$type": "Campaign",
  "play": "play:lead-reactivation@1",
  "path": [
    "reactivated-pipeline",
    "opened-deals-and-trials",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "reactivated-pipeline",
    "unit": "per-100",
    "heldBack": 29,
    "decision": null
  },
  "readout": {
    "value": 6.6,
    "n": 218,
    "maturing": 33,
    "interval": [
      0.4,
      12.8
    ],
    "readability": "C",
    "basis": "held-back",
    "pooled": false
  },
  "ledger": {
    "spend": 3,
    "workerCost": 13,
    "hours": 6.8,
    "pipelineArr": 4800,
    "wonArr": 4375,
    "projectedArr": 1168,
    "paybackDays": 1
  }
}

Outside benchmark: the record’s reactivation-demo-requests-unanswered range, from a vendor-run field test of business demo requests, finds most go unanswered, which is the pool own-the-miss works.

Before it · After it. Before it: lead-nurture hands its silent exits here after 60 days, and events-and-webinars its quiet registrants. After it: Interested replies go to the AE, and a lost Deal or a closed-lost reason goes back to its owner.

Example

Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days) on 612 pooled records: 47 merged or released, 36 refused or invalid, 29 held back, and 251 Messages delivered against 229 matches. Read every captured thread at ?threads=all; three follow the tables.

What happened, agent half, by optionDecisionsDeliveredDeals or trials openedWon (credited, not all caused by this Play)
Send the reason18218282 on Pro, 1 on Team
Own the miss · Founder writes it33 · 1433 · 143 · 21 on Pro · 1 on the $2,400 plan (+$2,393 ARR)
To the AE · Not now · Let them go9 · 211 · 64—9 Meetings booked—
Agent half · held back513229 matched, 251 sent with rounds13 of 196 matured · 0 of 22$4,375 · $0
At 120 a month (the Use it when volume)about 260 a month120held back at randomOther Startups’ results: +5.1 per 100, ■■■□ Likely, n 14,600
DayEventWhat happenedYour time
0event_132 Campaign.createdthe three steps; dry run fails collection-record and mailbox-warm30 min
1event_150 Contact.importedthe 300 spreadsheet rows imported again with their collecting Forms; 40 refused20 min
2event_163 Meeting.bookedthe first Meeting from a reactivated Lead, a founder note to a past Meeting—
9event_301 Role.staffedAE · Priya Shah (person) takes role:sales-lead—
16event_352 Role.updatedpromoted: rounds send after a 2-minute hold, 46 of 50 drafts passed—
28 · 49event_540 Change.merged · event_870 Readout.createdthe 0.8 match line: replayed at 0 of 40 wrong matches, read back at +21d at 1 of 375 min
44event_745 Campaign.pausedunanswered-positive: an Interested reply waited 78 min; resumed when Priya claimed it5 min
1–56event_140 Approval.created, first of 50you reviewed 50 drafts and wrote 14 founder notes, from the POST /{namespace}/tasks/next log4.6 h · total 6.8 h measured, 7 h asked

Leaseline’s agent → Teo Marsh, Granite Row, Oct 2, 09:00 · On Mar 3 you asked whether Leaseline handles a second owner on one portfolio. Nobody answered you; that was our miss.¹ It does now: per-owner renewal batches shipped on Sep 28.² https://leaseline.app/changelog/per-owner Want it on in a trial with your 64 units?³ *Signed by Leaseline’s agent, named as an agent, with the why-you and stop lines.*⁴

Teo, Oct 2, 11:15 · “Yes, start the trial.” POST /{namespace}/offers/{offer}/trial opened it, and Granite Row paid for Pro on Oct 14, +$347 ARR.

Granite Row, 2026-10-01 · the draft watched-event refused, then the rewrite that sent
- I saw you were back on our pricing page this week, so I wanted to reach out.
+ On Mar 3 you asked whether Leaseline handles a second owner on one portfolio. Nobody answered you; that was our miss.

Brookside Flats, 2026-10-06 14:10 · replied to the Team price round: “Yes, the 60-unit price works. Can we talk Thursday?” The agent chose To the AE, Brief attached, due 15:10. · Priya, 14:31 · claimed it with POST /{namespace}/tasks/{task}/claim and booked Thursday 10:00; the Deal opened Oct 9. The Brief is in When it hands to you (task_486).

¹ What he did with Leaseline, with its date, and the miss owned in one clause. ² A fresh reason with its public source, the changelog. ³ One ask, at Behavior grade. ⁴ The fixed lines, compiled from the Role’s Settings.

Your settings

plays/lead-reactivation.mdx
---
holdout: 0.1      # 1 in 10 newly eligible records per List gets no Message for 60 days
---
Match by reason code first, then by model at 0.8 or more; park the rest.
People who had a call with us get a note I write myself.
Text
$ npx startup-builder show plays/lead-reactivation
holdout 0.1 · match line 0.8 · founder notes for first tier     your file  plays/lead-reactivation.mdx:2,4,5 (Ask 2026-08-24; line 4 by change_31, 2026-09-21)
family demand · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences reactivation-round, reactivation-round-founder, reactivation-tray-founder · checks owned-by-a-person, customer-collision, approved-pages, watched-event, verification, market-hold · stops 11 · placements gmail, outlook, yahoo-mail, linkedin    catalog  play:lead-reactivation@1 (Not live yet, gaps #5)

Every key from the catalog

Key Id What it is
Tactic reactivation-pool Reactivation pool: Turns every record the Startup collected and no other Play holds into a deduped, verified, tiered queue, with a randomized holdout. Starts at Sends nothing.
Tactic reason-match Reason match: Matches each pooled record to one fresh announced reason with a public source, by reason code and then by model match, or parks it. Starts at Sends nothing.
Tactic reactivation-compose Reactivation compose: Fills three fields of the segment template from the record and its reason, or briefs the founder on first-tier records, then runs the critic pass. Starts at You approve each one.
Tactic send-gate-check Send gate check: Checks Suppression, a live reason, the Market, the basis stamp, the Person-month grant, the facts and the labels before any cold Message exists. Starts at Sends nothing.
Tactic reactivation-send Reactivation send: Sends each passed draft from the Person’s last correspondent or the labeled agent in ramped waves, and closes each round after 7 silent days. Starts at It does it, you can stop it.
Tactic reply-matrix Reply matrix: Labels every outreach reply with one of 11 labels, maps it to one of seven reply kinds, and runs that kind’s move by its deadline. Starts at You approve each one.
Tactic sending-stop-loss Sending stop loss: Reads the Play’s own bounces, replies and seed tests on every send, and rests, pauses or retires a Mailbox, Domain, cell or the Play. Starts at Sends nothing.
Tactic reactivation-readout Reactivation readout: Reads Deals opened per 100 delivered against the holdout by segment, tier, reason kind and age band, with trust cost beside it. Starts at Sends nothing.
Trigger form-ghosted Form ghosted: state on Visitor.identified, window 730d.
Trigger nurture-handoff Nurture handoff: at on Lead.nurtured, window 365d.
Trigger registrant-silent Registrant silent: state on Gathering.registered, window 365d.
Trigger trial-lapsed Trial lapsed: at on Offer.trialed, window 365d.
Trigger records-imported Records imported: event on Contact.imported, window 730d.
Trigger need-shipped Need shipped: event on Version.deployed, window 30d.
Trigger answer-owed Answer owed: event on Content.published, window 30d.
Trigger offer-changed Offer changed: event on Offer.published, window 30d.
Trigger gathering-announced Gathering announced: event on Gathering.opened, window 21d.
Trigger outcome-fact Outcome fact: event on Content.published, window 30d.
Trigger hiring Opening published: event on Opening.published, window 30d.
Trigger funding Funding: at on Company.funded, window 45d.
Trigger not-now-date Not now date: at on Conversation.answered, window 14d.
Trigger known-return Known return: event on Visitor.identified, window 72h.
Sequence reactivation-round Reactivation round: 6 steps; it ends on Any reply; A bounce; Suppression at any scope; An open Deal; A paid Order or Subscription; A restore; A new Form or Registration; An Enrollment in another Play; An expired reason.
Sequence reactivation-round-founder Reactivation round founder: 4 steps; it ends on Any reply; A bounce; Suppression at any scope; An open Deal; A paid Order or Subscription; A new Form or Registration; An expired reason; The Mandate paused or revoked.
Sequence reactivation-tray-founder Reactivation tray founder: 1 steps; it ends on Any reply; Suppression at any scope; An open Deal; An expired reason; The Mandate paused or revoked.
Benchmark reactivation-demo-requests-unanswered Share of B2B demo requests that got no email reply from the company: 68 % (A data vendor’s demo-request field experiment; a market baseline, not a lift; its method is never reused, 2026-09-22).
Benchmark reactivation-webinar-show-rate Share of webinar registrants who attended, total attendees over total registrations: 32 % (A webinar-platform vendor’s 2026 B2B webinar benchmark, 2025 data; its own customers only, 2025-12-31).

Compiled, not written: edit the Play record lead-reactivation and its Leaseline run, 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.