Warm intros
Finds who already knows each company you want, and that person asks them first, from their own account, before any introduction.
- Channel
- Email and inboxes
- Kind
- Outreach
Be our SDR: find who among our investors, advisors and happy Customers knows the companies on our list, and draft my ask to them. They ask the company first, from their own account; nobody is introduced without a yes. I send every ask myself. 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":"warm-intros"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'warm-intros' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"warm-intros"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'warm-intros' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "warm-intros can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "fail",
"observed": "1 of 4 introducers opted in; 120 companies on your List",
"doc": "/plays/ warm-intros#check-use-when",
"fix": "Send each introducer their opt-in page; it passes at 3.",
"then": "Message.schedule"
},
…
Hand our latest intro path 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(%22Thing.related%22%2C%20%22Person.announced%22%2C%20%22Agreement.signed%22%2C%20%22Outcome.delivered%22%2C%20%22Action.answered%22%2C%20%22Message.received%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_1316"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22prospect_22%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%22prospect_22%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Thing.related", "Person.announced", "Agreement.signed", "Outcome.delivered", "Action.answered", "Message.received")', 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 (\"Thing.related\", \"Person.announced\", \"Agreement.signed\", \"Outcome.delivered\", \"Action.answered\", \"Message.received\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1316"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"prospect_22\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"prospect_22\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Thing.related\", \"Person.announced\", \"Agreement.signed\", \"Outcome.delivered\", \"Action.answered\", \"Message.received\")', 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_358",
"$type": "Decision",
"choice": "ask-the-introducer",
"reason": "Marcus Bell sat on Grayson Property Group’s board until 2025: grade 82, over the 70 line in your file; 1 of his 3 asks this quarter used",
"stakes": "medium",
"options": [
"ask-the-introducer",
"wait-for-their-mark",
"opt-in-check",
"reply-to-the-intro",
"thank-them",
"not-now"
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_2 puts the ask to Marcus in your send tray: 96 words, with his opt-in check and Leaseline’s 80-word blurb below. Nothing sends until you press Send.
4.7 introductions per 10 asks against 2.2 before · before-after,
| Try another: the company | Choice | Reason |
|---|---|---|
| Grayson Property Group, through Marcus Bell (angel): grade 82 | ask-the-introducer | over the 70 line, 1 of his 3 asks used |
| Hollis Lane Rentals, through Lena Ortiz (advisor): grade 55 | wait-for-their-mark | under 70: she marks how well she knows them first |
| Marcus Bell answered yes for Crestview Homes | opt-in-check | the introducer said yes |
| Rosa at Birchway wrote to you and Tom at Pinegate together | reply-to-the-intro | an introduction reached you |
| Northfield Rentals said no to Lena on Sep 12 | not-now | a no holds every touch for 90 days |
- Day 5: first introduction made
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Intro acceptance rate → New Leads → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +1.9 introductions per 10 asks (Other Startups’ results; no lift of your own yet) × 13 asks a month × 0.29 won per introduction × $1,029 first order ARR ≈ +$737. Under First signal: At 13 asks a month, 90 days can tell only +3 per 10 or more, so your file starts at holdout: and reads before-after.
sample · api.sb/
Start it this week
npx startup-builder add play warm-intros # 1 · writes plays/warm-intros.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":"warm-intros"}'
# 3 · keep it; every ask waits for your Send
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"warm-intros"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/warm-intros \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: no path is picked; introducers keep their pages
curl -X PATCH https://api.sb/leaseline.app/campaigns/warm-intros \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when fail · Not live yet, gaps #8 | Send each introducer their opt-in page; it passes at 3. | POST /{namespace}/messages/{message}/schedule |
domain-authenticated pass | Nothing to fix: the Domain is set up for email. | POST /{namespace}/domains/{domain}/authenticate |
baseline warn · Not live yet, gaps #8 | n 9: it reads before-after, not proof, until volume allows a held-back half. | POST /{namespace}/metrics/query |
role-unstaffed warn · Not live yet, gaps #8 | Staff the AE, or leave it: every Meeting from an introduction comes to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "warm-intros can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "fail",
"observed": "1 of 4 introducers opted in; 120 companies on your List",
"doc": "/plays/warm-intros#check-use-when",
"fix": "Send each introducer their opt-in page; it passes at 3.",
"then": "Message.schedule"
},
{
"check": "domain-authenticated",
"status": "pass",
"observed": "leaseline.app, 3 records resolve",
"doc": "/plays/warm-intros#check-domain-authenticated",
"fix": "Nothing to fix: the Domain is set up for email.",
"then": "Domain.authenticate"
},
{
"check": "baseline",
"status": "warn",
"observed": "2 introductions from 9 asks in 90 days",
"doc": "/plays/warm-intros#check-baseline",
"fix": "n 9: it reads before-after, not proof, until volume allows a held-back half.",
"then": "Metric.query"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"sales-lead"
],
"owned": 31,
"doc": "/plays/warm-intros#check-role-unstaffed",
"fix": "Staff the AE, or leave it: every Meeting from an introduction comes to you.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · fail (gaps #8): 1 of 4 introducers opted in | POST /{namespace}/messages/{message}/schedule each introducer’s opt-in page from your Mailbox; 3 opted in by day 2 | 10 min | their yes, 2 days here |
domain-authenticated · pass: leaseline.app resolves | POST /{namespace}/domains/{domain}/authenticate | 0 min | none |
baseline · warn: 2 of 9 in 90 days | POST /{namespace}/metrics/query on intro-acceptance-rate; it fills Before in Your number | 0 min | none |
role-unstaffed · warn (gaps #8): 31 of your open Leads have a person owner, you | POST /{namespace}/roles/{role}/staff, or leave it: Meetings come to you | 0 min | none |
Your number · Before 2.2 per 10 · Now 4.7 introductions per 10 asks · Target 4 by Dec 31 · before-after,
Each path briefed costs about $0.05 (Worker cost); the path map reads who knows whom, never a message body. Thank-yous are the same for every answer, at most 4 a year to one introducer, under your $300 gift Limit. That comes to about $1.20 a month at 24 asks, plus thank-yous.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| The nightly path map finds a tie of grade 70 or more to a company on your List | intro-path | event on Thing.related where grade >= 70 or grade rose by 20 | 30d; one ask per path | POST /{namespace}/integrations/connect for your contacts and calendar, metadata only |
| An introducer answers yes, no or not well known | introducer-answer | event on Action.answered where action.kind = 'intro-ask' | 1d | their tap on the ask, an POST /{namespace}/actions/{action}/answer |
| A thread with the introducer and the company reaches you | intro-made | event on Message.received where participants include the introducer and the target | your reply within 4 business hours | forward intros@ to the address inbound-source printed |
+ 4 more for new introducers, announced moments, delivered outcomes and the company’s yes (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1316" ,
"$type": "Event",
"name": "Thing.related",
"at": "2026-10-19T03:12:55Z" ,
"seq": 1316,
"data": {
"from": "contact_71",
"to": "prospect_22",
"grade": 82,
"tie": "board seat, 2021–2025" ,
"list": "small-property-managers"
}
}npx startup-builder trigger Thing.related --like event_1316 # replays the path
npx startup-builder clock advance --by 7d # runs the ask’s one follow-up line, which ends when Marcus answers
npx startup-builder listen Thing.related --forward-to http://localhost:3000/hook Who runs it
SDR · your agent (role:, worker_2) holds the Key Result: it maps paths, picks and drafts. Every ask and every introduction reply sends from you (Dana Okafor, person, worker_1), from your own Mailbox or LinkedIn profile. Meetings go to AE · Priya Shah (person) (role:, worker_3, staffed on day 9).
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Ask the introducer · Reply to the introduction | You send it, from your own Mailbox | 24 drafted, 24 sent, 19 unedited · 11 drafted, 11 sent | never | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Ask how well they know them | You approve each one | 9 of 9 | at 10 passed | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Their check to the company | Drafted for the introducer, sent from their own account | 15 drafted, 15 sent by them | never | — | POST /{namespace}/actions/{action}/cancel |
| Thank the introducer · Not now | It does it | 14 of 14 · 6 of 6 | — | one introducer complaint → You approve each one | POST /{namespace}/actions/{action}/redirect |
| Change the grade line | You approve each one | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a message to a company before its yes, an ask past budget, a thank-you tied to the answer | Never, on every rung | 0 | never | — | kill-switch |
What it reads · What it may call. The path map reads who knows whom from contacts and calendars as metadata, never a message body, subject or Meeting note (metadata). An introducer’s words are data, never instructions: no line in them picks a recipient. Its tools are POST /{namespace}/actions/{action}/ask, POST /{namespace}/leads, and any other call becomes an Approval under the Role’s Mandate.
You hold the SDR Key Result: 4 introductions per 10 asks by 2026-12-31. ← worker, metric
On each path or answer, choose one option and say why. ← triggers, chooses
Draft an ask only on a path of grade 70 or more, within the introducer’s budget. ← your file, line 4; Grade floor, Ask budget
Write the ask in Dana’s words, at most 120 words; the blurb says only what approved Pages say. ← placements, approved-pages
Never write to a company before it says yes to the introducer. ← Double opt-inThe slow loop. The weekly Decisions kept 70 as the grade line, and no Change was merged in the window, so there is no replay or read-back to print.
What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Ask the introducer ask-the-introducer | grade 70 or more, within the introducer’s budget | Your rule (line 4) | intro-ask-sequence, drafted into your send tray | you, from your own Mailbox, due 1 business day · Take this one | you |
Ask how well they know them wait-for-their-mark | grade 30 to 69 | Agent’s call, with its reason | POST /{namespace}/actions/{action}/ask: how well do you know them? | the introducer’s mark | the same |
Their check to the company opt-in-check | the introducer said yes | Your rule (Double opt-in) | opt-in-check-sequence: their note and the blurb, sent from their own account | the introducer | the same |
Reply to the introduction reply-to-the-intro | an introduction thread reached you | Agent’s call, with its reason | intro-follow-through with the introducer to bcc → POST /{namespace}/leads | you, within 4 business hours · Take this one | you |
Thank the introducer thank-them | an introduction, a Meeting or a Deal | Your rule (thanks) | introducer-thanks-sequence, the same for every answer | nobody | the same |
Not now not-now | a no in the last 90 days, or no budget left | Your rule (Target decline, Ask budget) | nothing; names the hold and when it ends | nobody | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | Marcus: “Yes, happy to ask her.” | his opt-in check is drafted for him to send from his own account | the introducer | — | POST /{namespace}/actions/{action}/answer (theirs) |
| Send me pricing | Tom at Pinegate: “What does it cost for 200 units?” | your reply is drafted with the Pricing Page’s list Price | you | 4 business hours | POST /{namespace}/conversations/{conversation}/answer |
| Not now | Lena: “Not a good time to ask him.” | the ask closes; the path waits 90 days | nobody | at once | GET /{namespace}/decisions |
| Wrong person | Marcus: “I know her, but Sam runs ops there.” | asks whether he knows Sam; it never writes to Sam | SDR · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | the follow-up line waits for the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | Lena: “What should I tell her you do for owners?” | To you, with the blurb and the approved Pages | you | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | an introducer: “Please stop asking me for intros.” | asks to that Person end, across your other Startups too, within the hour | nobody | within 1 h | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
Every ask and every introduction reply is yours to send; Meetings go to AE · Priya Shah (person). One Brief per Role, as captured (brief and draft are Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_548" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-20T17:00:00Z" ,
"on": "prospect_22",
"brief": {
"who": "Marcus Bell, angel, for Grayson Property Group (260 units, 5 owners)" ,
"chose": "ask-the-introducer",
"why": "his board seat 2021–2025, grade 82; 1 of his 3 asks this quarter used" ,
"draft": "in your send tray, 96 words" ,
"never": [
"a word to Grayson before their yes",
"a thank-you tied to his answer"
]
}
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_511" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-08T15:30:00Z" ,
"on": "lead_66",
"brief": {
"who": "Tom Reyes, Pinegate Rentals, introduced by Rosa at Birchway" ,
"said": "Rosa says you fixed her renewals. We have 200 units.",
"chose": "reply-to-the-intro",
"why": "an introduction reached you",
"draft": "your reply, with Rosa moved to bcc and 3 times on Priya’s calendar"
}
}
]You answer with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect, each a one-call window, and nothing in your tray sends until you press Send. A reply to an introduction past 4 business hours counts toward late-reply; an ask nobody sends in 3 business days counts toward tray-silence.
On time: you, 10 of 11 introductions answered within 4 business hours, median 1 h 50 m, n 11, ■■□□ Early sign beside Other Startups’ 91 %. Your queue: in week 1, 6 asks to send; then about 3 asks and 1 introduction reply 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) | Refuses | Fix | Then |
|---|---|---|---|
owned-by-a-person (rule j, gaps #8) | a draft to a company whose Lead or open Deal a person owns | Leave it to the person who owns it: the draft waits in their queue. | POST /{namespace}/tasks/{task}/assign |
keep-first (rule j, gaps #8) | an intro ask to a Customer introducer who is at risk, past due or has an unsubscribe pending | Let their CSM reach them first, then ask again once they are healthy. | POST /{namespace}/tasks/next |
customer-ask-cap (gaps #3) | a second open ask to one Customer introducer in a window, from any Play | review-requests holds Rosa until Nov 1. | GET /{namespace}/decisions |
double-opt-in (the record’s Double opt-in) | any Message from you to a company before it said yes to the introducer | Wait for their yes on the introducer’s thread. | GET /{namespace}/decisions |
opt-in (the record’s Opt-in gate) | an ask to an investor, advisor or Customer who has not opted in on their page | Send their opt-in page first. | POST /{namespace}/messages/{message}/schedule |
ask-budget (the record’s Ask budget) | an ask past the introducer’s open-ask or 90-day budget, across your other Startups | Pick another introducer, or wait for the budget to reset. | GET /{namespace}/decisions |
grade-floor (the record’s Grade floor) | an ask on a path under grade 70 without the introducer’s own mark | Ask the introducer how well they know them. | POST /{namespace}/actions/{action}/ask |
target-decline (the record’s Target decline) | any touch for 90 days, and any ask for 180, after a company’s no | It waits; the date it ends is on the hold. | GET /{namespace}/decisions |
approved-pages (Not live yet) | a blurb or ask sentence that no approved Page backs | Cut the sentence, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Grayson thread in Example.
| Check | Fix | Then |
|---|---|---|
approved-pages fail · Not live yet, gaps #8 | Cut the sentence, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
double-opt-in pass | — | GET /{namespace}/decisions |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The ask to Marcus Bell for Hollis Lane did not reach your tray: its blurb says Leaseline cut late renewals 80 % for Birchway, which no approved Page says.",
"checks": [
{
"check": "approved-pages",
"status": "fail",
"doc": "/plays/warm-intros#check-approved-pages",
"fix": "Cut the sentence, or publish the Page that says it.",
"then": "Site.publish"
},
{
"check": "double-opt-in",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "late-reply",
"observed": "3 introductions answered past 4 business hours",
"bound": "2 in 30 days",
"window": "30d"
},
"doc": "/plays/warm-intros#stop-late-reply" ,
"task": "task_487"
}
]Did it work
At 13 asks a month, 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).
4.7 introductions per 10 asks against 2.2 before · before-after,
- Chose
- ask-the-introducer
- Why
- Marcus Bell sat on Grayson Property Group’s board until 2025: grade 82, over the 70 line in your file; 1 of his 3 asks this quarter used
- From
- ask-the-introducer · wait-for-their-mark · opt-in-check · reply-to-the-intro · thank-them · not-now
- Expects
- an introduction thread for prospect_22 within 30d
- Reopens when
- no Action.answered from contact_71 within 7d
- By
- worker_2
JSON
{
"$id": "decisions/decision_358",
"$type": "Decision",
"choice": "ask-the-introducer",
"reason": "Marcus Bell sat on Grayson Property Group’s board until 2025: grade 82, over the 70 line in your file; 1 of his 3 asks this quarter used",
"stakes": "medium",
"options": [
"ask-the-introducer",
"wait-for-their-mark",
"opt-in-check",
"reply-to-the-intro",
"thank-them",
"not-now"
],
"by": "worker_2",
"on": "prospect_22",
"expected": "an introduction thread for prospect_22 within 30d",
"reopensWhen": "no Action.answered from contact_71 within 7d"
}| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
|---|---|---|---|---|---|
intro-acceptance-rate | 4.7 per 10: 9 introductions from 19 matured asks · 5 still maturing | 2.2 per 10: 2 of 9 | — | — | before-after, not proof · Other Startups’ results +1.9 per 10, ■■■□ Likely, n 3,020 |
new-leads | 11 Leads from introductions, 7 Meetings held | 1.2 (2 in 90 days, per 56) | — | — | before-after |
new-arr ↑ | $3,087, 3 Customers · Booked: credited, not all caused by this Play | $216 | — · Worth about +$740 a month | — | before-after · 2 trials still deciding |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
The leaf counts introductions made within 30 days of the ask per 10 asks sent: the company said yes, and a thread with both people reached you. Before against after reads one window against the 90 days before it; it is not proof, and Other Startups’ results print beside it.
How it moves it: the company hears about Leaseline from someone it trusts, who asked its yes first; 15 of 24 introducers said yes, and 11 of their 15 companies did.
Guardrails: before against after: Meetings held per introduction, 7 of 11, and introducer complaints, 0 in 24 asks against a floor of 2 in 50; 6 companies said no and are held 90 days.
{
"$id": "https://api.sb/leaseline.app/campaigns/warm-intros" ,
"$type": "Campaign",
"play": "play:warm-intros@1" ,
"path": [
"intro-acceptance-rate",
"new-leads",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "intro-acceptance-rate",
"unit": "per-10",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 19,
"maturing": 5,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 96,
"workerCost": 2,
"hours": 4.1,
"pipelineArr": 2393,
"wonArr": 3087,
"projectedArr": 737,
"paybackDays": 9
}
}Outside benchmark: a warm introduction is answered about 5 times as often as a cold email to the same buyer (a sales-engagement firm’s study of 1.2M first touches, 2026-07-15).
Before it · After it. Before it: review-requests and customer-referrals bring Customer introducers past their first outcome. After it: instant-response answers the companies that write back, and the paths it never asks feed cold-email and linkedin-outbound.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 5 of 7 introducers opted in, the path map found 46 paths of grade 70 or more to 120 companies, and you sent 24 asks. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | What came of it | Won (credited, not all caused by this Play) |
|---|---|---|---|
| Ask the introducer | 24, each sent by you | 15 introducers said yes | — |
| Their check to the company · Reply to the introduction | 15 · 11 | 11 companies said yes · 11 replies by you, 7 Meetings held | 2 on Pro, 1 on the $2,400 plan (+$3,087 ARR), 2 trials still deciding |
| Ask how well they know them · Thank the introducer · Not now | 9 · 14 · 6 | 4 marked 70 or more · 14 thank-yous, $96 of $300 · 6 held | — |
| At 3 introducers (the Use it when volume) | about 10 asks in 56 days | before-after, not proof | Other Startups’ results: +1.9 per 10, ■■■□ Likely, n 3,020 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_119 Campaign.created | the three steps; dry run fails use-when: 1 of 4 introducers opted in | 10 min |
| 2 | event_150 Consent.created, the third | 3 introducers opted in; the first path map ran that night | 10 min |
| 5 | event_203 Message.received | the first introduction: Rosa at Birchway to Tom at Pinegate | 10 min |
| 9 | event_301 Role.staffed | AE · Priya Shah (person) takes role:; Meetings move to her calendar | — |
| 24 | event_520 Action.refused | approved-pages refused a blurb; rewritten once and drafted again | 5 min |
| 38 | event_702 Campaign.paused | late-reply: 3 introductions past 4 business hours; you cleared the tray | 25 min |
| 1–56 | event_131 Task.assigned, first of 35 | you sent 24 asks and 11 replies; weekly reviews, from the POST /{namespace}/tasks/next log | 3.3 h · total 4.1 h measured, 4 h asked |
Dana → Marcus Bell, Oct 19, 09:20 · Marcus, you know Grayson’s team from your board years.¹ Would you ask Ana whether she’d take a note from me about renewal notices across their 5 owners? Your check and an 80-word blurb are below; if she says no, that’s the end of it.² Dana
Marcus, Oct 19, 11:02 · tapped Yes and sent his check from his own account.
Action.answered; Ana said yes at 16:40, and Dana’s reply went out at 17:05.
- Leaseline cut late renewals by 80 % for Birchway, and Hollis Lane would see the same.
+ Leaseline sends every renewal notice 60 days out, per owner, so nothing slips between owners. Rosa → Dana and Tom Reyes, 2026-10-08 11:30 · “Tom runs 200 units at Pinegate; Leaseline fixed our renewals.” · the reply was drafted at 11:31 with Rosa to bcc and 3 times on Priya’s calendar; Dana sent it at 13:05, inside the 4 business hours. The Brief is
task_511(When it hands to you).
¹ Only the tie the path map read, never a message body. ² The ask closes on any answer, and the thank-you is the same either way.
Your settings
---
holdout: 0 # 13 asks a month is too few to hold any back; it reads before-after
---
Ask only on a path of grade 70 or more, at most 3 asks a quarter to one introducer.
I send every ask and every reply myself.$ npx startup-builder show plays/warm-intros
holdout 0 · grade line 70 · 3 asks a quarter your file plays/warm-intros.mdx:2,4,5 (Ask 2026-08-24)
family demand · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences intro-ask-sequence, opt-in-check-sequence, intro-follow-through, introducer-thanks-sequence · checks owned-by-a-person, keep-first, customer-ask-cap, double-opt-in, opt-in, ask-budget, grade-floor, target-decline, approved-pages · stops 9 · placements gmail, outlook, linkedin, postal-mail catalog play:warm-intros (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record warm-intros 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.