Skip to content

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
Run oneMode try
You, to your agent

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"
  }
}
Response200application/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 yetPreview

On 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, not proof · n 19 · path → arr

Try another: the companyChoiceReason
Grayson Property Group, through Marcus Bell (angel): grade 82ask-the-introducerover the 70 line, 1 of his 3 asks used
Hollis Lane Rentals, through Lena Ortiz (advisor): grade 55wait-for-their-markunder 70: she marks how well she knows them first
Marcus Bell answered yes for Crestview Homesopt-in-checkthe introducer said yes
Rosa at Birchway wrote to you and Tom at Pinegate togetherreply-to-the-introan introduction reached you
Northfield Rentals said no to Lena on Sep 12not-nowa no holds every touch for 90 days

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: 0 and reads before-after.

sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Thing.related · first ask drafted 9m 30s after the path · 8 keys Not live yet

Start it this week

Terminal
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"}'
422Refusedwarm-intros can’t start yet: 1 check fails and 2 warn.
CheckFixThen
use-when fail · Not live yet, gaps #8Send each introducer their opt-in page; it passes at 3.POST /{namespace}/messages/{message}/schedule
domain-authenticated passNothing to fix: the Domain is set up for email.POST /{namespace}/domains/{domain}/authenticate
baseline warn · Not live yet, gaps #8n 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 #8Staff 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.

CheckFix (one call)Your timeWait
use-when · fail (gaps #8): 1 of 4 introducers opted inPOST /{namespace}/messages/{message}/schedule each introducer’s opt-in page from your Mailbox; 3 opted in by day 210 mintheir yes, 2 days here
domain-authenticated · pass: leaseline.app resolvesPOST /{namespace}/domains/{domain}/authenticate0 minnone
baseline · warn: 2 of 9 in 90 daysPOST /{namespace}/metrics/query on intro-acceptance-rate; it fills Before in Your number0 minnone
role-unstaffed · warn (gaps #8): 31 of your open Leads have a person owner, youPOST /{namespace}/roles/{role}/staff, or leave it: Meetings come to you0 minnone

Your number · Before 2.2 per 10 · Now 4.7 introductions per 10 asks · Target 4 by Dec 31 · before-after, not proof · n 19 matured

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

WhenTrigger idStarts onWindowHow it gets in
The nightly path map finds a tie of grade 70 or more to a company on your Listintro-pathevent on Thing.related where grade >= 70 or grade rose by 2030d; one ask per pathPOST /{namespace}/integrations/connect for your contacts and calendar, metadata only
An introducer answers yes, no or not well knownintroducer-answerevent on Action.answered where action.kind = 'intro-ask'1dtheir tap on the ask, an POST /{namespace}/actions/{action}/answer
A thread with the introducer and the company reaches youintro-madeevent on Message.received where participants include the introducer and the targetyour reply within 4 business hoursforward intros@ to the address inbound-source printed
+ 4 more for new introducers, announced moments, delivered outcomes and the company’s yes (?lanes=all)
One signed delivery · StartupBuilder-Signature
{
  "$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"
  }
}
Reproduce it in test
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:prospector, 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:sales-lead, worker_3, staffed on day 9).

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Ask the introducer · Reply to the introductionYou send it, from your own Mailbox24 drafted, 24 sent, 19 unedited · 11 drafted, 11 sentnever—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Ask how well they know themYou approve each one9 of 9at 10 passed—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Their check to the companyDrafted for the introducer, sent from their own account15 drafted, 15 sent by themnever—POST /{namespace}/actions/{action}/cancel
Thank the introducer · Not nowIt does it14 of 14 · 6 of 6—one introducer complaint → You approve each onePOST /{namespace}/actions/{action}/redirect
Change the grade lineYou approve each one0 mergednever—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 answerNever, on every rung0never—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.

The brief (folded): compiled Agent-register Markdown · play:warm-intros@1 · each line names its record key
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-in

The 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

OptionPicked whenDecided byRunsHands toIf it’s just you
Ask the introducer ask-the-introducergrade 70 or more, within the introducer’s budgetYour rule (line 4)intro-ask-sequence, drafted into your send trayyou, from your own Mailbox, due 1 business day · Take this oneyou
Ask how well they know them wait-for-their-markgrade 30 to 69Agent’s call, with its reasonPOST /{namespace}/actions/{action}/ask: how well do you know them?the introducer’s markthe same
Their check to the company opt-in-checkthe introducer said yesYour rule (Double opt-in)opt-in-check-sequence: their note and the blurb, sent from their own accountthe introducerthe same
Reply to the introduction reply-to-the-introan introduction thread reached youAgent’s call, with its reasonintro-follow-through with the introducer to bcc → POST /{namespace}/leadsyou, within 4 business hours · Take this oneyou
Thank the introducer thank-theman introduction, a Meeting or a DealYour rule (thanks)introducer-thanks-sequence, the same for every answernobodythe same
Not now not-nowa no in the last 90 days, or no budget leftYour rule (Target decline, Ask budget)nothing; names the hold and when it endsnobodythe same
When they write backFixture replyWhat happensWho answersBy whenCall
InterestedMarcus: “Yes, happy to ask her.”his opt-in check is drafted for him to send from his own accountthe introducer—POST /{namespace}/actions/{action}/answer (theirs)
Send me pricingTom at Pinegate: “What does it cost for 200 units?”your reply is drafted with the Pricing Page’s list Priceyou4 business hoursPOST /{namespace}/conversations/{conversation}/answer
Not nowLena: “Not a good time to ask him.”the ask closes; the path waits 90 daysnobodyat onceGET /{namespace}/decisions
Wrong personMarcus: “I know her, but Sam runs ops there.”asks whether he knows Sam; it never writes to SamSDR · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Oct 28the follow-up line waits for the return datenobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answerLena: “What should I tell her you do for owners?”To you, with the blurb and the approved Pagesyou1 business dayPOST /{namespace}/conversations/{conversation}/escalate
Stopan introducer: “Please stop asking me for intros.”asks to that Person end, across your other Startups too, within the hournobodywithin 1 hPOST /{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).

What lands in each queue · sample
[
  {
    "$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)RefusesFixThen
owned-by-a-person (rule j, gaps #8)a draft to a company whose Lead or open Deal a person ownsLeave 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 pendingLet 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 Playreview-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 introducerWait 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 pageSend 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 StartupsPick 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 markAsk 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 noIt 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 backsCut the sentence, or publish the Page that says it.POST /{namespace}/sites/{site}/publish
Stop (pauses the Play)Pauses whenThen
decline-streak2 no or don’t-know answers in a row from one introducer; 2 unanswered asks in a rowtheir budget halves for 90 days; at 2 unanswered they pause
introducer-stopan introducer says stopasks to them end everywhere within the hour
goodwill2 introducer complaints in any 50 asksYou approve each one for 30 days; every budget halves
acceptance-floorunder 1 introduction per 10 asks after 30 asksnew asks stop
late-reply3 introductions answered past 4 business hours in 30 daysnew asks pause until you clear the tray
tray-silence3 business days with nothing sent from your traypicking and drafting stop until you return
kill-switchyou press itevery ask and both Mandates pause; introducer pages stay
+ 3 more for the path map and LinkedIn lanes (?lanes=all)

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.

422RefusedThe 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.
CheckFixThen
approved-pages fail · Not live yet, gaps #8Cut 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.

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "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, not proof · n 19 · path → arr

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"
}
NodeNow (56 days)Before (the 90 days, per 56)AddedConfidenceBasis
intro-acceptance-rate4.7 per 10: 9 introductions from 19 matured asks · 5 still maturing2.2 per 10: 2 of 9——before-after, not proof · Other Startups’ results +1.9 per 10, ■■■□ Likely, n 3,020
new-leads11 Leads from introductions, 7 Meetings held1.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 · arrcarried from new-arrcarried——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.

The Campaign card · sample
{
  "$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=all; three follow the tables.

What happened, by optionDecisionsWhat came of itWon (credited, not all caused by this Play)
Ask the introducer24, each sent by you15 introducers said yes—
Their check to the company · Reply to the introduction15 · 1111 companies said yes · 11 replies by you, 7 Meetings held2 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 now9 · 14 · 64 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 daysbefore-after, not proofOther Startups’ results: +1.9 per 10, ■■■□ Likely, n 3,020
DayEventWhat happenedYour time
0event_119 Campaign.createdthe three steps; dry run fails use-when: 1 of 4 introducers opted in10 min
2event_150 Consent.created, the third3 introducers opted in; the first path map ran that night10 min
5event_203 Message.receivedthe first introduction: Rosa at Birchway to Tom at Pinegate10 min
9event_301 Role.staffedAE · Priya Shah (person) takes role:sales-lead; Meetings move to her calendar—
24event_520 Action.refusedapproved-pages refused a blurb; rewritten once and drafted again5 min
38event_702 Campaign.pausedlate-reply: 3 introductions past 4 business hours; you cleared the tray25 min
1–56event_131 Task.assigned, first of 35you sent 24 asks and 11 replies; weekly reviews, from the POST /{namespace}/tasks/next log3.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.

Hollis Lane, 2026-09-17 · the blurb approved-pages refused, then the rewrite that sent
- 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

plays/warm-intros.mdx
---
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.
Text
$ 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

Key Id What it is
Tactic introducer-roster Introducer roster finds the Holders, advisors, Customers and Portfolio founders who may introduce the Startup, and enrolls each only on their own opt-in. Starts at You approve each one.
Tactic path-map Path map rebuilds each night the ties between introducers and targets from metadata, connected accounts, tick lists and public overlap, and grades each tie. Starts at Sends nothing.
Tactic tie-check Tie check asks an enrolled introducer to mark which mid-grade targets they know, once a month at most, and turns each mark into a grade. Starts at You approve the first wave.
Tactic intro-pick Intro pick chooses each weekday the paths worth an ask inside every budget, one path per target, and holds out 1 eligible path in 10. Starts at Sends nothing.
Tactic intro-ask Intro ask drafts the founder’s ask, the introducer’s opt-in check and a forwardable blurb, and sends the ask from the founder after approval. 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 fabrication-veto Fabrication veto blocks any draft written in a Human’s name that states a number, name, event, quote or feeling no source supports. Starts at Sends nothing.
Tactic linkedin-send-tray LinkedIn send tray shows each request and Message with its reason, for the Human to check, copy and send in the Venue’s own app. Starts at You approve each one.
Tactic opt-in-check Opt-in check gives each introducer a private page to answer an ask, edit the check, send it themselves and record the target’s answer. Starts at You approve each one.
Tactic intro-watch Introduction watch finds each introduction in the founder’s Mailbox, drafts the founder’s reply within 15 minutes, and holds the founder to 4 business hours. Starts at You approve each one.
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 introducer-thanks Introducer thanks sends every introducer who answers the same note and chosen thank-you, whatever the answer, then reports a Meeting or a Deal. Starts at It does it, you can stop it.
Tactic intro-readout Intro readout computes introductions made per 10 asks each week, with goodwill per introducer, class and Variant comparisons, the holdout and the decay check. Starts at Sends nothing.
Trigger intro-path Intro path: event on Thing.related, window 30d.
Trigger announced-moment Announced moment: event on Person.announced, window 21d.
Trigger introducer-joined Introducer joined: event on Agreement.signed, window 14d.
Trigger delivered-outcome Delivered outcome: event on Outcome.delivered, window 7d.
Trigger introducer-answer Introducer answer: event on Action.answered, window 1d.
Trigger target-opt-in Target opt-in: event on Action.answered, window 2d.
Trigger intro-made Intro made: event on Message.received, window 4h.
Sequence intro-ask-sequence Intro ask sequence: 3 steps; it ends on Any tap or reply from the introducer; The introducer taps Stop; Suppression of either Person; The kill switch.
Sequence opt-in-check-sequence Opt-in check sequence: 3 steps; it ends on The target says yes or no; The introducer taps No answer; The introducer taps Stop.
Sequence intro-follow-through Intro follow-through: 4 steps; it ends on A booked Meeting; Any target reply, handed to the reply matrix; Suppression or a removal ask.
Sequence introducer-thanks-sequence Introducer thanks sequence: 4 steps; it ends on The introducer taps Stop updates; The third update is sent; The introducer taps Stop.
Benchmark network-intros-core-share Share of B2B go-to-market leaders who call network and intros a core motion: 62 % (An annual State of B2B GTM survey, 2026-10-14).
Benchmark cmo-word-of-mouth-first Share of CMOs who rank word of mouth their first consideration factor when buying software: 42 % (A buyer-side survey of how B2B SaaS CMOs buy software, 2026-02-04).
Benchmark cmo-cold-outreach-first Share of CMOs who rank cold outreach their first consideration factor when buying software: 2 % (A buyer-side survey of how B2B SaaS CMOs buy software, 2026-02-04).

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.