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.
- Step
- Make the sale
- Channel
- Sequences
- Kind
- Conversion
- Summary
- startupbuilder.dev
Be our SDR for follow-up: every Lead who hasn’t bought gets notes keyed to what they did, most in the first month. Big accounts get a note from me on day 3. Stop the moment they buy, reply or go quiet for 90 days. Show me what’s missing; don’t send.
# Not live yet (gaps #2)
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-nurture"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'lead-nurture' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-22 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"lead-nurture"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'lead-nurture' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-22 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "lead-nurture can’t start: 2 checks fail and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "34 new Leads a month not bought or booked within 7 days",
"doc": "/plays/ lead-nurture#check-use-when",
"then": "Metric.query"
},
{
…
Hand our latest Lead who stalled 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(%22Lead.qualified%22%2C%20%22Conversation.answered%22%2C%20%22Conversation.closed%22%2C%20%22Visitor.identified%22%2C%20%22Customer.activated%22%2C%20%22Entitlement.checked%22%2C%20%22Offer.trialed%22%2C%20%22Order.started%22%2C%20%22Event.captured%22%2C%20%22Version.deployed%22%2C%20%22Meeting.booked%22%2C%20%22Waitlist.admitted%22%2C%20%22Approval.approved%22%2C%20%22Monitor.checked%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_1211"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22lead_61%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_61%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Lead.qualified", "Conversation.answered", "Conversation.closed", "Visitor.identified", "Customer.activated", "Entitlement.checked", "Offer.trialed", "Order.started", "Event.captured", "Version.deployed", "Meeting.booked", "Waitlist.admitted", "Approval.approved", "Monitor.checked")', 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 (\"Lead.qualified\", \"Conversation.answered\", \"Conversation.closed\", \"Visitor.identified\", \"Customer.activated\", \"Entitlement.checked\", \"Offer.trialed\", \"Order.started\", \"Event.captured\", \"Version.deployed\", \"Meeting.booked\", \"Waitlist.admitted\", \"Approval.approved\", \"Monitor.checked\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1211"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"lead_61\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"lead_61\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Lead.qualified\", \"Conversation.answered\", \"Conversation.closed\", \"Visitor.identified\", \"Customer.activated\", \"Entitlement.checked\", \"Offer.trialed\", \"Order.started\", \"Event.captured\", \"Version.deployed\", \"Meeting.booked\", \"Waitlist.admitted\", \"Approval.approved\", \"Monitor.checked\")', 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"
}
}application/json{
"decision": {
"$id": "https: //api.sb/ leaseline.app/ decisions/ decision_437",
"$type": "Decision",
"choice": "self-serve-branch",
"reason": "Ivy Chen at Copper Oak Rentals (38 units) is on the free plan and added no owner 24 hours after signup; the rescue step sends the one next step",
"stakes": "low",
"options": [
"self-serve-branch",
"assisted-branch",
"answer-what-they-asked",
"recap-and-offer-times",
"rescue-the-checkout",
"to-the-ae",
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_2 is the rescue note, held for Ivy’s quiet hours until 08:00 her time. It ends the moment she adds an owner, replies or buys.
17.6 per 100 against 7.3 before · before-after,
| Try another: the Lead | Choice | Reason |
|---|---|---|
| Ivy Chen, Copper Oak Rentals: free plan, no owner added after 24 h | self-serve-branch | a free-plan Lead short of the first step |
| Marcus Webb, Northgate Living: 160 units, asked a question, booked no time | assisted-branch | over the 120-unit line; your note goes on day 3 |
| Ola Reyes: started Pro checkout at 14:10, no Order by 15:10 | rescue-the-checkout | a started checkout with no Order in 60 minutes |
| Hilltop Rentals: 95 units, on the pricing Page Oct 13 and Oct 16 | to-the-ae | a fit Lead back on pricing 2 days in 7 |
- Day 3: first nurtured Lead books a Meeting
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Nurture conversion → New paying Customers → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +4 paid per 100 enrolled (Other Startups’ results; no lift of your own to read) × 35 enrolled a month × $410 first order ARR ≈ +$574. Under First signal: Each Lead reads at day 90; at 35 a month, 90 days can tell only +14 per 100 or more, so your file starts at holdout: and reads before-after.
sample · api.sb/
Start it this week
npx startup-builder add play lead-nurture # 1 · writes plays/lead-nurture.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 2026-06-22
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-nurture"}'
# 3 · keep it, at You approve each one for the first 20 Leads
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"lead-nurture"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/lead-nurture \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: no note sends; service touches still send
curl -X PATCH https://api.sb/leaseline.app/campaigns/lead-nurture \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | 34 new Leads a month not bought or booked within 7 days | POST /{namespace}/metrics/query |
baseline pass · Not live yet, gaps #8 | 7.3 paid per 100 within 90 days, n 41 | POST /{namespace}/metrics/query |
marketing-purpose fail | Add the marketing Purpose to your signup and Form copy; until then only service touches send. | POST /{namespace}/sites/{site}/publish |
domain-authenticated fail | Add the 3 DNS records shown; it passes once they resolve, often within an hour. | POST /{namespace}/domains/{domain}/authenticate |
mailbox-warm pass · Not live yet, gaps #1 | the Startup’s Mailbox, warm since May | POST /{namespace}/mailboxes/{mailbox}/warm |
role-unstaffed warn · Not live yet, gaps #8 | Staff the AE, or leave it: call asks come to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "lead-nurture can’t start: 2 checks fail and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "34 new Leads a month not bought or booked within 7 days",
"doc": "/plays/lead-nurture#check-use-when",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "pass",
"observed": "7.3 paid per 100 within 90 days, n 41",
"doc": "/plays/lead-nurture#check-baseline",
"then": "Metric.query"
},
{
"check": "marketing-purpose",
"status": "fail",
"doc": "/plays/lead-nurture#check-marketing-purpose",
"fix": "Add the marketing Purpose to your signup and Form copy; until then only service touches send.",
"then": "Site.publish"
},
{
"check": "domain-authenticated",
"status": "fail",
"doc": "/plays/lead-nurture#check-domain-authenticated",
"fix": "Add the 3 DNS records shown; it passes once they resolve, often within an hour.",
"then": "Domain.authenticate"
},
{
"check": "mailbox-warm",
"status": "pass",
"observed": "the Startup’s Mailbox, warm since May",
"doc": "/plays/lead-nurture#check-mailbox-warm",
"then": "Mailbox.warm"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"sales-lead"
],
"owned": 9,
"doc": "/plays/lead-nurture#check-role-unstaffed",
"fix": "Staff the AE, or leave it: call asks come to you.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · pass: 34 a month; 7.3 per 100, n 41 (gaps #8) | POST /{namespace}/metrics/query on nurture-conversion, which fills Before in Your number | 1 min | none |
marketing-purpose · fail (gaps #8) | POST /{namespace}/sites/{site}/publish the signup and Form copy with the Purpose | 10 min | none |
domain-authenticated · fail | POST /{namespace}/domains/{domain}/authenticate | 10 min | until DNS resolves, often under 1 h |
mailbox-warm · role-unstaffed · pass; warn (gaps #8): 9 of your open Leads have a person owner, you | POST /{namespace}/roles/{role}/staff, or leave it: call asks come to you, and the agent drafts into your queue for your 9 | 0 min | none |
Your number · Before 7.3 per 100 · Now 17.6 per 100 · Target 20 by Dec 31 · before-after,
Each note costs under $0.01 to fill (Worker cost), and sending runs on the shared broadcast stream at no charge. Your founder notes cost your 2 minutes each. That comes to about $3 a month at 35 enrolled Leads.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A new Lead routes to nurture or self-serve | lead-routed-nurture | event on Lead.qualified where route in ('nurture', 'self-serve') | 24h | from instant-response or your signup, through POST /{namespace}/leads/{lead}/qualify |
| A signup has not reached the first step 24 hours later | activation-stalled | state on Visitor.identified where no activation Event 24 hours after signup | 7d | your app calls POST /{namespace}/events/capture on the first step |
| A known Lead starts checkout and places no Order in 60 minutes | checkout-abandoned | state on Order.started where a known Lead and no Order.placed within 60 minutes | 48h | POST /{namespace}/integrations/connect (Stripe) |
+ 11 more for non-bookers, the first step reached, free limits, trial ends, pricing returns, interest matches, no-shows, waitlist admits, account holds and 90 silent days (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1211" ,
"$type": "Event",
"name": "Visitor.identified",
"at": "2026-10-19T09:12:30Z" ,
"seq": 1211,
"data": {
"lead": "leads/lead_61" ,
"name": "Ivy Chen",
"organization": "Copper Oak Rentals",
"units": 38,
"plan": "free",
"signedUpAt": "2026-10-18T09:12:30Z" ,
"activated": false
}
}# 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":"Visitor.identified","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Visitor.identified --like event_1211 # replays the delivery
npx startup-builder clock advance --by 1d # runs the rescue step unless she adds an owner firstWho runs it
SDR · your agent (role:, worker_2) holds the Key Result and picks each step from what the Lead did. Your day-3 notes to big accounts hand to you (Dana Okafor, person, worker_1), and call asks go to AE · Priya Shah (person) (role:, worker_3, staffed on day 72). Notes from the agent are signed by the agent, named as an agent.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Self-serve notes · Start with what they asked for · Recap and offer times | It does it, you can stop it | 20 Leads reviewed, 0 edits on the last 10 | met on day 21 | a step-stop → You approve each one, for that template | POST /{namespace}/actions/{action}/cancel inside the hold |
| Assisted notes and a founder note | You approve each one | 19 notes, 2 edited | never: a note in your name stays yours | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Rescue the checkout | It does it, you can stop it | 7 of 7 | met on day 21 | the refund-quality Stop → You approve each one | POST /{namespace}/actions/{action}/cancel |
| To the AE · Let them go | It does it | 6 of 6 · 21 of 21 | — | an unanswered-reply Stop → You approve each one | POST /{namespace}/actions/{action}/redirect |
| Change the step rule | You approve each one | 1 merged of 1 | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a deadline or discount the Offer lacks; a Visit or Page view in a note | Refused, every time | 2 drafted, 2 refused | never | — | the approved-pages Check |
What it reads · What it may call. It reads what each Lead did in Leaseline and said in their own words, and never names a Visit or a Page view in a note. It may call POST /{namespace}/contacts/{contact}/enroll, POST /{namespace}/messages/{message}/schedule and POST /{namespace}/leads/{lead}/assign; POST /{namespace}/meetings/book lands on the AE’s calendar under the AE’s name. Its tools are POST /{namespace}/meetings/book, POST /{namespace}/tasks/{task}/assign, and any other call becomes an Approval under the Role’s Mandate.
You hold the SDR Key Result: 20 paid per 100 enrolled Leads by 2026-12-31. ← worker, metric
On each Lead Event, choose one option and say why; at 90 silent days, Let them go. ← triggers, chooses
At 120 units or more, the founder writes a note on day 3. ← your file, line 4
Send the closest paid step when they add their first owner, not on a fixed day. ← your file, line 5
Fill at most three fields; the template holds the Offer, the signature and the stop line. ← copyRules 4
No deadline, countdown or discount the Offer record lacks. ← copyRules 5, approved-pages The slow loop, as a Change. decision_301 (2026-09-07, weekly) read 7 of 24 self-serve Leads paying when the closest-paid note followed their first owner within a day, against 2 of 19 when it went on day 4, so change_16 keyed that note to the first owner (your file, line 5), and Dana merged it with POST /{namespace}/changes/{change}/merge. Replayed on past Leads, POST /{namespace}/changes/{change}/review put the branch at 21 per 100; read back at +30d it is 19 per 100, n 21, ■□□□ Too early to tell (Example, day 107).
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.
npx startup-builder eval --scenario lead-nurture-136 --agent "claude -p" --seat prospector # seated: 17.6 per 100, 0 Checks failed sent, $0.02 a Lead · yours: 16.1, 1 discount drafted, $0.03 → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Self-serve notes self-serve-branch | a free-plan or trial Lead | Your rule (the route) | nurture-self-serve: the rescue, the made note, then the closest paid step on the first owner | nobody; it ends when they buy | the same |
Assisted notes and a founder note assisted-branch | a fit Lead at or over the 120-unit line who has not booked | Your rule (line 4) | nurture-assisted → your nurture-founder-note on day 3 | you approve the note, due 1 business day · Take this one | you |
Start with what they asked for answer-what-they-asked | they came from a piece, a free tool, a Gathering or an outreach reply | Agent’s call, with its reason | nurture-interest, starting with what they asked for | nobody | the same |
Recap and offer times recap-and-offer-times | a Form or chat answer offered a time and they booked none | Your rule (the non-booker window) | form-non-booker or chat-non-booker: a recap and two new times, once | nobody | the same |
Rescue the checkout rescue-the-checkout | a started checkout with no Order in 60 minutes | Your rule (the checkout window) | checkout-rescue-two-touch: the restored checkout and one answer, then the stated guarantee | nobody | the same |
To the AE to-the-ae | a reply asking for a call, a fit Lead back on pricing 2 days in 7, or a missed Meeting | Agent’s call, with its reason | POST /{namespace}/meetings/book with the AE’s times → POST /{namespace}/tasks/{task}/assign | POST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 60 min (response-60m), Brief attached · Take this one | you, within 60 min |
Let them go let-them-go | 90 silent days, or day 180 | Your rule (the exit) | nothing; lead-reactivation holds them after a 60-day rest, with every fact and Offer used | nobody | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Can we walk through it for our 160 units?” | To the AE: three times from Priya’s calendar; notes stop | AE · Priya Shah (person) | 60 min | POST /{namespace}/meetings/book |
| Send me pricing | “What does Pro cost for 38 units?” | answers with the Pricing Page’s list Price and one next step | SDR · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “We’ll look again in spring.” | notes stop; one note returns on the date they named | SDR · your agent | at once | POST /{namespace}/messages/{message}/schedule |
| Wrong person | “My business partner handles software.” | asks them to forward it; it never writes to an address from their text | SDR · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | the next step waits for the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “Can you import from our old spreadsheet?” | To a person, the question in the Brief | AE · Priya Shah, or you | 60 min | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Stop emailing me.” | every note stops, on every scope they chose; service touches about their own account still send | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
Day-3 notes in your name go to you (Dana Okafor, person); call asks, pricing returns and no-shows go to AE · Priya Shah (person), and before day 72 they came to you. As captured, one Brief per Role (brief, draft, route and checks are Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/approvals/approval_97" ,
"$type": "Approval",
"verdict": null,
"deadline": "2026-10-20T15:00:00Z" ,
"draft": "Marcus, you asked whether Leaseline handles 4 owners on one portfolio. It does; that is why I built it. Want 15 minutes on Thursday?" ,
"route": "assisted-branch",
"checks": [
{
"check": "approved-pages",
"status": "pass"
},
{
"check": "owned-by-a-person",
"status": "pass"
}
]
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_527" ,
"$type": "Task",
"assignee": "worker_3",
"due": "2026-10-16T15:20:00Z" ,
"on": "lead_47",
"brief": {
"who": "Hilltop Rentals, 95 units" ,
"did": "the pricing Page on Oct 13 and Oct 16; Team plan open both days" ,
"chose": "to-the-ae",
"why": "a fit Lead back on pricing 2 days in 7",
"never": [
"a discount",
"a deadline the Offer lacks"
]
}
}
]You answer a founder note with POST /{namespace}/approvals/{approval}/approve, an edit, or POST /{namespace}/approvals/{approval}/refuse; one unanswered by its deadline expires, and the branch carries on without it. 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 notes to that Lead 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-reply fires.
On time: AE · Priya Shah: 6 of 6 claimed within 60 min, median 21 min, n 6. You: 17 of 19 founder notes approved by their deadline, n 19, ■■□□ Early sign beside Other Startups’ 89 % on time. Your queue: counted by kind: in week 1, about 12 note reviews a day; after day 21, about 1 founder note and 1 AE hand-off a week, and 1 weekly readout.
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) | Refuses | Fix | Then |
|---|---|---|---|
owned-by-a-person (rule j; Not live yet, gaps #8) | a note to a Contact whose Lead or open Deal a person owns, or whose Conversation a person claimed | Leave it to the person who owns it: the draft waits in their queue. | POST /{namespace}/tasks/{task}/assign |
customer-collision (gaps #1) | a nurture note to a Contact with an active Subscription | Send it to their CSM instead. | POST /{namespace}/conversations/{conversation}/assign |
approved-pages (Not live yet) | a price, plan, limit, deadline or discount that the claims source and the Offer record lack | Cut the line, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
marketing-purpose (the Consent gate) | a promotional note with no marketing Purpose valid in the Lead’s Market | Only service touches send; add the Purpose to your copy. | POST /{namespace}/sites/{site}/publish |
claims-hold | a queued note after a claims change, before its prices, plans and limits are checked again | Wait for the re-check, often under 10 min. | GET /{namespace}/decisions |
collision-hold | a note to a Person with an open Conversation on any channel | It waits until the Conversation closes. | POST /{namespace}/conversations/{conversation}/close |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Elm Street thread in Example.
| Check | Fix | Then |
|---|---|---|
approved-pages fail · Not live yet, gaps #8 | Cut the line, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
owned-by-a-person pass · Not live yet, gaps #8 | — | POST /{namespace}/tasks/{task}/assign |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The month-one close to Elm Street Rentals did not send: it carries a deadline and a discount no Offer holds.",
"checks": [
{
"check": "approved-pages",
"status": "fail",
"doc": "/plays/lead-nurture#check-approved-pages",
"fix": "Cut the line, or publish the Page that says it.",
"then": "Site.publish"
},
{
"check": "owned-by-a-person",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "unanswered-reply",
"observed": "2h 10m",
"bound": "60m",
"window": "1 reply"
},
"doc": "/plays/lead-nurture#stop-unanswered-reply" ,
"task": "task_498"
}
]Did it work
At about 8 enrolled a week, no held-back half reads within 90 days, so the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Each figure’s call is POST /{namespace}/metrics/query by node, and every node above the leaf is Not live yet (gaps #4).
17.6 per 100 against 7.3 before · before-after,
- Chose
- self-serve-branch
- Why
- Ivy Chen at Copper Oak Rentals (38 units) is on the free plan and added no owner 24 hours after signup; the rescue step sends the one next step
- From
- self-serve-branch · assisted-branch · answer-what-they-asked · recap-and-offer-times · rescue-the-checkout · to-the-ae · let-them-go
- Expects
- the first owner added within 3d
- Reopens when
- no Customer.activated for lead_61 within 3d
- By
- worker_2
JSON
{
"$id": "decisions/decision_437",
"$type": "Decision",
"choice": "self-serve-branch",
"reason": "Ivy Chen at Copper Oak Rentals (38 units) is on the free plan and added no owner 24 hours after signup; the rescue step sends the one next step",
"stakes": "low",
"options": [
"self-serve-branch",
"assisted-branch",
"answer-what-they-asked",
"recap-and-offer-times",
"rescue-the-checkout",
"to-the-ae",
"let-them-go"
],
"by": "worker_2",
"on": "lead_61",
"expected": "the first owner added within 3d",
"reopensWhen": "no Customer.activated for lead_61 within 3d"
}| Node | Now (119 days) | Before (the 90 days before) | Added | Confidence | Basis |
|---|---|---|---|---|---|
nurture-conversion | 17.6 per 100: 6 of 34 matured Leads paid within 90 days · 102 still maturing | 7.3 per 100: 3 of 41, with no nurture | — · Worth about +$570 a month | — | before-after, not proof · Other Startups’ results +4 per 100, ■■■□ Likely, n 9,800, 10 % held back at random |
new-paying-customers | 15 nurtured Leads paid, 6 of them matured | 3 | — | — | before-after |
new-arr ↑ | $6,393, 15 Customers (13 on Pro, 2 on Team) · Booked: credited, not all caused by this Play | $1,041 | — · 11 trials still deciding | — | before-after, not proof |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
Before against after reads Leads enrolled Jun 22 to Jul 21, matured at day 90, against the 41 Leads of the 90 days before, who got no nurture. It is not proof; Other Startups’ results, read against 10 % held back at random at enrollment, print beside it.
How it moves it: each step fires within an hour of what the Lead did, and the closest paid step follows the first owner they add instead of a fixed day 4.
Guardrails: before against after: outside-paying-customers, 15 against 3, and spam-rate, 0.04 % of 1,880 notes; stops at 0.6 % of delivered.
{
"$id": "https://api.sb/leaseline.app/campaigns/lead-nurture" ,
"$type": "Campaign",
"play": "play:lead-nurture@1" ,
"path": [
"nurture-conversion",
"new-paying-customers",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "nurture-conversion",
"unit": "percent",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 34,
"maturing": 102,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 0,
"workerCost": 11,
"hours": 9.5,
"pipelineArr": 4800,
"wonArr": 6393,
"projectedArr": 574,
"paybackDays": 1
}
}Outside benchmark: the record’s nurture-month-one-plan-upgrades range, from a subscription-analytics firm’s billing data, puts most first plan upgrades in a subscriber’s first month, which is why the notes are front-loaded there.
Before it · After it. Before it: instant-response routes Nurture and trial Leads here, and product-led signups. After it: every purchase goes to onboarding, call asks to the AE, and Let them go hands Leads to lead-reactivation after a 60-day rest.
Example
Leaseline ran it from 2026-06-22 to 2026-10-19 (119 days): 136 Leads enrolled, 34 matured past day 90 and 102 still maturing, and 1,880 notes sent. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Notes sent | Paid (credited, not all caused by this Play) |
|---|---|---|---|
| Self-serve notes | 78 | 1,190 | 10 on Pro |
| Assisted notes and a founder note | 19 | 214 + 19 founder notes | 2 on Team, 1 on Pro |
| Start with what they asked for · Recap and offer times · Rescue the checkout | 14 · 12 · 7 | 201 · 24 · 13 | 1 · 0 · 1 on Pro |
| To the AE · Let them go | 6 · 21 | — | 4 Meetings held, 2 Deals open |
| All · Before (90 days) | 157 | 1,880 | 15 (6 of 34 matured) · 3 of 41 |
| At 35 a month (the Use it when volume) | about 40 a month | about 480 a month | Other Startups’ results: +4 per 100, ■■■□ Likely, n 9,800 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_101 Campaign.created | the three steps; dry run fails marketing-purpose and domain-authenticated | 35 min |
| 2 | event_108 Site.published | the marketing Purpose on your signup and Form copy | 10 min |
| 3 | event_113 Meeting.booked | the first nurtured Lead books a call, from the recap note | — |
| 21 | event_160 Role.updated | promoted: notes send after a 2-minute hold, 20 Leads reviewed, 0 edits on the last 10 | — |
| 72 | event_301 Role.staffed | AE · Priya Shah (person) takes role: | — |
| 77 · 107 | event_315 Change.merged · event_820 Readout.created | the closest paid note keyed to the first owner: replayed at 21 per 100, read back at +30d at 19, n 21 | 5 min |
| 98 | event_640 Campaign.paused | unanswered-reply: a call ask waited 2h 10m; enrollments resumed once Priya answered | 5 min |
| 1–119 | event_104 Approval.created, first of 239 | you reviewed 220 notes in weeks 1 to 3 and approved 19 founder notes | 8.2 h · total 9.5 h measured, 10 h asked |
Leaseline’s agent → Noor Haddad, Elm Street Rentals, Jul 3, 08:05 · You signed up yesterday; the one step left is adding your first owner, which takes about 2 minutes.¹ https://leaseline.app/owners/new *Signed by Leaseline’s agent, named as an agent, with the stop line.*²
Noor, Jul 3, 08:40 · added her first owner. Jul 3, 09:30 · the closest paid note: Pro sends that owner’s renewal batch 60 days out, for $29 a month.³ Jul 16 · paid for Pro, +$347 ARR.
- Upgrade by Friday to keep 20% off Pro.
+ Pro sends each owner their renewal batch, 60 days out, for $29 a month. Want it on for your 22 units? Hilltop Rentals, 2026-10-16 14:20 · back on the pricing Page for a second day in a week, Team open both times. The agent sent no note and chose To the AE, Brief attached, due 15:20. · Priya, 14:38 · claimed it with
POST /{namespace}/tasks/{task}/claimand wrote with three times; they booked Oct 21. The Brief is in When it hands to you (task_527).
¹ What she did in Leaseline, in her own terms; never a Page view. ² The fixed signature and stop lines, compiled from the Role’s Settings. ³ The Pricing Page’s list Price, and one ask.
Your settings
---
holdout: 0 # 8 a week is too few to hold 1 in 10 back; it reads before-after
---
At 120 units or more, I write a note on day 3.
Send the closest paid step when they add their first owner, not on a fixed day. $ npx startup-builder show plays/lead-nurture
holdout 0 · founder note at 120 units · closest paid on the first owner your file plays/lead-nurture.mdx:2,4,5 (Ask 2026-06-22; line 5 by change_16, 2026-09-07)
family demand · worker role:prospector, owns never · chooses 7 (5 rule, 2 read) · sequences nurture-self-serve, nurture-assisted, nurture-founder-note, nurture-interest, nurture-waitlist, form-non-booker, chat-non-booker, checkout-rescue-two-touch · checks owned-by-a-person, customer-collision, approved-pages, marketing-purpose, claims-hold, collision-hold · stops 9 · placements gmail, outlook, yahoo-mail catalog play:lead-nurture@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record lead-nurture 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.