Skip to content

Account visits

Finds the fitting companies behind visits to your own buying pages and writes to the right person there, from facts, never from the visit.

Channel
Who’s visiting
Run oneMode try
You, to your agent

Hand the latest company that read our buying pages 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(%22Visit.recorded%22%2C%20%22Visitor.identified%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_1412"}'

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

const { events: [last] } = await $.Event.list({ where: 'name in ("Visit.recorded", "Visitor.identified")', 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 (\"Visit.recorded\", \"Visitor.identified\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1412"}' --try   # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"organization_131\""}'   # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"organization_131\""}'   # Not live yet (gaps #7)
{
  "name": "do",
  "arguments": {
    "code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Visit.recorded\", \"Visitor.identified\")', 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_455",
    "$type": "Decision",
    "choice": "write-to-them",
    "reason": "Fernhill Property Group read pricing on 2 days in 4 (7 points, confirmed on 2 networks), and its careers page lists 2 leasing coordinator openings",
    "stakes": "low",
    "options": [
      "write-to-them",
      "write-as-you",
      "ads-only",
      "to-their-csm",
      "not-now",
      "let-it-go"
  …
sample · 4 Not live yetPreview

On POST /{namespace}/processes/{process}/enableOff POST /{namespace}/processes/{process}/pauseTake this one POST /{namespace}/tasks/{task}/claim

action_3 is touch 1 to Marta Silva (contact_14), Fernhill’s head of operations, held until 08:40 her time; touch 2 waits in the same thread for 6 days and drops if the stack decays first.

18.2 qualified responses per 100 against 2.9 before · before-after, not proof · n 22 · path → arr

Try another: the visiting companyChoiceReason
Fernhill Property Group: pricing on 2 days in 4, 2 leasing roles openwrite-to-them7 points, confirmed, with a public fact to write from
Calloway Residential: pricing and the security page, 900 unitswrite-as-youa top-tier account: it goes out as Dana
Northgate Lettings: one setup-docs read, a probable matchads-only3 points and probable: it joins the company Audience only
Juniper Homes: an active Customer on Proto-their-csmalready a Customer

Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Visit reply lift → New Leads → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +4.8 qualified responses per 100 (Other Startups’ results; no lift of your own yet) × 17 companies written to a month × 0.45 responses to Deals or trials × 0.30 opens to paid × $1,200 first order ARR ≈ +$132. Under First signal: At 4 companies a week, 90 days can tell only +22 per 100 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 Visit.recorded · first touch 19h after the second visit · 4 keys Not live yet

Start it this week

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

# 2 · dry run; below, its 422 on the day-0 Startup (clock at 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":"account-visits"}'

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

# on
curl -X POST https://api.sb/leaseline.app/processes/outbound/enable \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# off: lookups stop, nothing sends, the company Audience freezes
curl -X POST https://api.sb/leaseline.app/processes/outbound/pause \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
422Refusedaccount-visits can’t start yet: 2 checks fail and 1 warns.
CheckFixThen
owned-by-a-person pass · Not live yet, gaps #80 of the 104 fitting visiting companies have a Lead or open Deal a person ownsPOST /{namespace}/tasks/{task}/assign
use-when pass · Not live yet, gaps #83,410 visitors in 30 days, 17 fitting companies at 5 points or morePOST /{namespace}/metrics/query
baseline warn · Not live yet, gaps #8n 104: it reads before-after, not proof, until a held-back half can read.POST /{namespace}/metrics/query
visit-capture failServe your Site from your Domain and publish the visitor notice; lookups start when both pass.POST /{namespace}/domains/connect
domain-authenticated passleaseline.app: 3 of 3 records resolvePOST /{namespace}/domains/{domain}/authenticate
mailbox-warm fail · Not live yet, gaps #1Wait for the warm-up to finish, 14 days from day 0; ads-only keeps running.POST /{namespace}/mailboxes/{mailbox}/warm
role-unstaffed pass · Not live yet, gaps #8SDR and CSM are your agents; AE routes come to you until it is staffedPOST /{namespace}/roles/{role}/staff
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "account-visits can’t start yet: 2 checks fail and 1 warns.",
  "checks": [
    {
      "check": "owned-by-a-person",
      "status": "pass",
      "observed": "0 of the 104 fitting visiting companies have a Lead or open Deal a person owns",
      "doc": "/plays/account-visits#check-owned-by-a-person",
      "then": "Task.assign"
    },
    {
      "check": "use-when",
      "status": "pass",
      "observed": "3,410 visitors in 30 days, 17 fitting companies at 5 points or more",
      "doc": "/plays/account-visits#check-use-when",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "3 hand-raises from 104 fitting visiting companies in 90 days",
      "doc": "/plays/account-visits#check-baseline",
      "fix": "n 104: it reads before-after, not proof, until a held-back half can read.",
      "then": "Metric.query"
    },
    {
      "check": "visit-capture",
      "status": "fail",
      "doc": "/plays/account-visits#check-visit-capture",
      "fix": "Serve your Site from your Domain and publish the visitor notice; lookups start when both pass.",
      "then": "Domain.connect"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "observed": "leaseline.app: 3 of 3 records resolve",
      "doc": "/plays/account-visits#check-domain-authenticated",
      "then": "Domain.authenticate"
    },
    {
      "check": "mailbox-warm",
      "status": "fail",
      "doc": "/plays/account-visits#check-mailbox-warm",
      "fix": "Wait for the warm-up to finish, 14 days from day 0; ads-only keeps running.",
      "then": "Mailbox.warm"
    },
    {
      "check": "role-unstaffed",
      "status": "pass",
      "observed": "SDR and CSM are your agents; AE routes come to you until it is staffed",
      "doc": "/plays/account-visits#check-role-unstaffed",
      "then": "Role.staff"
    }
  ]
}

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

CheckFix (one call)Your timeWait
owned-by-a-person · use-when · pass: 0 person-owned; 3,410 visitors, 17 fitting companies a month (gaps #8)POST /{namespace}/metrics/query on visit-reply-lift1 minnone
baseline · warn: 3 of 104 in 90 days, so it reads before-afterPOST /{namespace}/metrics/query; it fills Before in Your number0 minnone
visit-capture · fail (Not live yet)POST /{namespace}/domains/connect so your Site serves from leaseline.app, then POST /{namespace}/sites/{site}/publish the visitor notice15 minthe first Visits, under 1 h
domain-authenticated · mailbox-warm · pass · fail: dana@ and sdr@ warmed 0 of 14 daysPOST /{namespace}/mailboxes/{mailbox}/warm; company Audiences fill meanwhile2 min14 days
role-unstaffed · pass (gaps #8)POST /{namespace}/roles/{role}/staff the AE when you hire one0 minnone

Your number · Before 2.9 per 100 · Now 18.2 qualified responses per 100 · Target 20 by Dec 31 · before-after, not proof · n 22 matured

Each lookup costs $0.01 per resolved network address, and misses are free; each draft costs $0.04 from your Domain (Worker cost). Contact and company data cost $0.06 per verified address (POST /{namespace}/contacts/{contact}/enrich). That comes to about $4 a month at 17 companies written to.

When it starts

WhenTrigger idStarts onWindowHow it gets in
A fitting company reads your pricing or comparison pagepricing-visitevent on Visit.recorded where a resolved company reads the pricing or comparison Pagesscored the same day; ignored after 72 hyour Site on your Domain records each Visit (POST /{namespace}/events/capture)
It returns to a buying page on a second day within 7repeat-visitthreshold on Visit.recorded where a buying Page on a second day within 7 daysadds 2 points; the stack decays in 7 daysthe same
It reads setup docs, an integration or the security pageevaluation-visitevent on Visit.recorded where page in ('setup docs', 'API reference', 'integration', 'case study', 'security') and organization resolved7 dthe same
+ 2 more for company surges and the person rung, off in your file (?lanes=all)
One signed delivery · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1412",
  "$type": "Event",
  "name": "Visit.recorded",
  "at": "2026-10-19T13:20:05Z",
  "seq": 1412,
  "data": {
    "organization": {
      "$id": "https://api.sb/leaseline.app/organizations/organization_131",
      "name": "Fernhill Property Group",
      "confidence": "confirmed"
    },
    "page": "pricing",
    "day": 2,
    "points": 7
  }
}
Reproduce it in test
# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":"Visit.recorded","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Visit.recorded --like event_1412   # replays the second visit
npx startup-builder clock advance --by 6d   # runs touch 2 in the same thread, unless the stack decayed

Who runs it

SDR · your agent (role:prospector, worker_2) holds the Key Result. It hands replies to AE · Priya Shah (person) (role:sales-lead, worker_3, staffed on day 9), top-tier accounts to you (Dana Okafor, person, worker_1), and Customers to CSM · your agent (worker_5). Your number links to Did it work.

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Write to themIt does it, you can stop it20 of 20 approved unedited, then 7 of 7met on day 31 (the first 20 drafts); capped hereany draft fails a Check, or visit-leak fires → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Write as youYou approve each one, on every rung4 of 4never—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Ads only · To their CSM · Not now · Let it goIt does it21 of 21 · 5 of 5 · 6 of 6 · 3 of 3—a held company written to anyway → You approve each onePOST /{namespace}/actions/{action}/redirect
Change the scoring or the fit lineYou approve each one0 mergednever—POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert
Never: a Visit, a page read or a time on site in a Message; the person rungTo a person, every time1 draft refused, 0 sentnever—POST /{namespace}/processes/{process}/pause

What it reads · What it may call. A Visit picks the company and the role; it never appears in a Message, a subject line or a follow-up. The body comes only from the company’s own public pages and your approved Pages, and every send links a why-you Page with one-press stops. Its tools are POST /{namespace}/messages/{message}/schedule, PATCH /{namespace}/audiences/{id}, POST /{namespace}/tasks/{task}/assign, and any other call becomes an Approval under the Role’s Mandate.

The brief (folded): compiled Agent-register Markdown · play:account-visits@1 · each line names its record key
You hold the SDR Key Result: 20 qualified responses per 100 companies written to by 2026-12-31. ← worker, metric
On each scored Visit, choose one option and say why.                             ← triggers, chooses
Write only to a confirmed fitting company at 5 points or more.                   ← your file, line 4
Open on a public fact about the company; never on the Visit.                     ← copyRules 1, visit-in-copy
Companies over 500 units go out as Dana, after her OK.                           ← your file, line 5
Never write to a Lead or Deal a person owns: draft it into their queue.          ← worker.owns, owned-by-a-person

The slow loop. The weekly Decisions kept the 5-point line, and no Change was merged in the window, so there is no replay or read-back to print.

Bring your own agent (folded) starts at It does it, you can stop it when it matches or beats the seated agent on the eval suite with 0 Visits named, and at You approve each one when it does not.

Terminal
npx startup-builder eval --scenario account-visits-36 --agent "claude -p" --seat prospector   # seated: 18.2 per 100, 0 Visits named, $0.05 a draft · yours: 15.0, 1 Visit named → You approve each one

What it can do next

OptionPicked whenDecided byRunsHands toIf it’s just you
Write to them write-to-themconfirmed, 5+ points, a role and a factAgent’s call, with its reasonvisit-two-touch: touch 1 at 08:40 their time, touch 2 in thread at day 6 (POST /{namespace}/messages/{message}/schedule)on reply, POST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 60 min · Take this oneyou, within 60 min
Write as you write-as-youover 500 units, or a senior buyerYour rule (line 5)visit-two-touch-founder from dana@, after your OKyou approve each one, due 1 business day · Take this oneyou
Ads only ads-only3 or 4 points, or probableYour rule (line 4)PATCH /{namespace}/audiences/{id} on the company Audience account-ads readsnobodythe same
To their CSM to-their-csman active CustomerYour rule (the fit gate)POST /{namespace}/tasks/{task}/assign with the pages they read, never sent to themCSM · your agentyou
Not now not-nowan open Deal or Conversation, a hold, or no verified addressYour rule (rule j)nothing; names the holder: the AE, the hold, or the missing addressthe Deal’s owner · Take this oneyou
Let it go let-it-gono fact to write from, or under the fit lineAgent’s call, with its reasonnothing; the stack decays in 7 daysnobodythe same
When they write backFixture replyWhat happensWho answersBy whenCall
Interested“Worth a look. Thursday afternoon?”offers times on the AE’s calendar; the Brief goes to the AE (When it hands to you)AE · Priya Shah (person)60 minPOST /{namespace}/meetings/book
Send me pricing“What does it cost for 180 units?”answers with the Pricing Page’s list Price and one next stepSDR · your agent5 minPOST /{namespace}/conversations/{conversation}/answer
Not now“We’re locked in until spring.”touch 2 drops; the company stays in the Audience and moves to NurtureSDR · your agentat oncePOST /{namespace}/leads/{lead}/nurture
Wrong person“Our COO, Ben, owns renewals.”asks Marta to bring Ben in; it never writes to a name from her textSDR · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Oct 27touch 2 waits for the return date, or drops if the stack decays firstnobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answer“Do you handle HOA dues as well as leases?”To the AE, the question in the BriefAE · Priya Shah (person)60 minPOST /{namespace}/conversations/{conversation}/escalate
Stop“Take us off your list.”nothing else sends to anyone at the company, and its Visits stop being matchednobodyat oncePOST /{namespace}/contacts/{contact}/suppress

When it hands to you

Replies go to AE · Priya Shah (person); top-tier drafts come to you; Customers go to CSM · your agent. Before day 9 every reply came to you. What lands in each queue, as captured: one Brief per Role, then the Approval (brief, draft, route and checks are Not live yet, gaps #7).

What lands in each queue · sample
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_244",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-09-29T15:12:00Z",
    "on": "lead_66",
    "brief": {
      "who": "Ines Duarte, Harbor Row Rentals",
      "said": "Worth a look. Thursday afternoon?",
      "chose": "write-to-them",
      "why": "pricing twice and a public post about 2 new owners",
      "never": [
        "mention a Visit or a page they read",
        "a price beyond the list",
        "a discount"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_251",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-06T17:00:00Z",
    "on": "organization_102",
    "brief": {
      "who": "Calloway Residential, 900 units",
      "chose": "write-as-you",
      "why": "over the 500-unit line; read pricing and the security page",
      "fact": "their news page: 3 new owners this year"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_258",
    "$type": "Task",
    "assignee": "worker_5",
    "due": "2026-10-08T17:00:00Z",
    "on": "customer_9",
    "brief": {
      "who": "Juniper Homes",
      "chose": "to-their-csm",
      "why": "an active Subscription on Pro",
      "read": "the Team plan page twice"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_64",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-06T17:00:00Z",
    "draft": "Hi Grace, Calloway’s news page says you took on 3 new owners this year…",
    "route": "write-as-you",
    "checks": [
      {
        "check": "visit-in-copy",
        "status": "pass"
      },
      {
        "check": "approved-pages",
        "status": "pass"
      }
    ]
  }
]

Each receiver answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, POST /{namespace}/actions/{action}/redirect, POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, each a one-call window, and an Approval unanswered by its deadline expires and the draft never sends. Once a person claims, touch 2 cancels with claimedByPerson (Not live yet, gaps #7), and every reply goes to the claimer’s queue. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate (AE to you), and person-promise fires.

On time: AE · Priya Shah, 4 of 4 replies claimed within 60 min, median 21 min, ■□□□ Too early to tell, n 4; you, 4 of 4 approvals by their deadline, n 4. Your queue: counted by kind: in weeks 1 to 4, 20 approvals; since, about 1 top-tier approval and 1 hand-off a week, plus the monthly match check of 50 companies.

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

When it won’t send

Check (refuses one send)RefusesFixThen
owned-by-a-person (rule j; Not live yet, gaps #8)a send to a Contact whose Lead or open Deal a person owns, or whose Conversation a person claimedLeave it to the person who owns it: the draft waits in their queue.POST /{namespace}/tasks/{task}/assign
customer-collision (Not live yet, gaps #1)a first touch to anyone at an active CustomerSend it to their CSM instead: the company leaves the List.POST /{namespace}/tasks/{task}/assign
holdany touch at a company another Play or a person holdsLeave it; the holder writes, or the hold ends.GET /{namespace}/decisions
visit-in-copya draft that names a Visit, a page read, a time on site or a returnOpen on a public fact about the company instead.POST /{namespace}/messages/{message}/schedule
approved-pages (Not live yet)a sentence no approved Page or the company’s own public page backsCut the sentence, or publish the Page that says it.POST /{namespace}/sites/{site}/publish
noticea lookup while your visitor notice omits company lookupsPublish the notice Version that names them.POST /{namespace}/sites/{site}/publish
marketa lookup for a Visit from a Market your file sets offLeave it, or turn the Market on in your file.POST /{namespace}/markets/{market}/enter
resolution-stopan Event, Audience row or draft for a network or person who asked to stop being matchedNothing to fix: it drops before scoring.GET /{namespace}/suppressions
decaya touch whose stack decayed before it sentIt expires; a new visit starts a new stack.GET /{namespace}/events
mailbox-warma first touch from a Mailbox still warmingWait for the warm-up to finish, 14 days from day 0; ads-only keeps running.POST /{namespace}/mailboxes/{mailbox}/warm
Stop (pauses the Play)Pauses whenThen
sending-stop-lossany sending gate trips: bounces over 3 %, complaints over 0.1 % or a blocklist hitboth touches pause on that Mailbox; POST /{namespace}/mailboxes/{mailbox}/rest
visit-leakone delivered Message names a Visit or a page readevery send pauses until the evals re-run and pass
tracking-complaintreplies that call it tracking pass 1 % of first touches, after 200company outreach pauses; Audiences continue
wrong-companyover 10 % wrong in the monthly check of 50 companiescompany outreach stops until the matcher is fixed
identify-agreementover 10 % of 30+ matched visitors who sign up disagree with their matchthat grain’s outreach halts
lift-floorthe lift interval sits at or under 0 after 600 companies a halfoutreach stops; the Audiences continue
kill-switchyou press itevery Tactic pauses, lookups stop and Audience adds freeze; POST /{namespace}/processes/{process}/enable after review
+ 2 more for the person rung, off in your file: wrong-person and its own kill switch (?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 Harbor Row thread in Example.

422RefusedTouch 1 to Harbor Row Rentals did not send: it names a page they read.
CheckFixThen
visit-in-copy failOpen on a public fact about the company instead.POST /{namespace}/messages/{message}/schedule
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": "Touch 1 to Harbor Row Rentals did not send: it names a page they read.",
  "checks": [
    {
      "check": "visit-in-copy",
      "status": "fail",
      "doc": "/plays/account-visits#check-visit-in-copy",
      "fix": "Open on a public fact about the company instead.",
      "then": "Message.schedule"
    },
    {
      "check": "owned-by-a-person",
      "status": "pass"
    }
  ]
}

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

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "reason": {
      "limit": "sending-stop-loss",
      "observed": "4.1 % bounces on sdr@leaseline.app",
      "bound": "3 %",
      "window": "7d"
    },
    "doc": "/plays/account-visits#stop-sending-stop-loss",
    "mailbox": "sdr@leaseline.app"
  }
]

Did it work

At about 4 companies 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).

18.2 qualified responses per 100 against 2.9 before · before-after, not proof · n 22 · path → arr

Chose
write-to-them
Why
Fernhill Property Group read pricing on 2 days in 4 (7 points, confirmed on 2 networks), and its careers page lists 2 leasing coordinator openings
From
write-to-them · write-as-you · ads-only · to-their-csm · not-now · let-it-go
Expects
a qualified response from Fernhill within 30d
Reopens when
no inbound Message from contact_14 within 30d
By
worker_2
JSON
{
  "$id": "decisions/decision_455",
  "$type": "Decision",
  "choice": "write-to-them",
  "reason": "Fernhill Property Group read pricing on 2 days in 4 (7 points, confirmed on 2 networks), and its careers page lists 2 leasing coordinator openings",
  "stakes": "low",
  "options": [
    "write-to-them",
    "write-as-you",
    "ads-only",
    "to-their-csm",
    "not-now",
    "let-it-go"
  ],
  "by": "worker_2",
  "on": "organization_131",
  "expected": "a qualified response from Fernhill within 30d",
  "reopensWhen": "no inbound Message from contact_14 within 30d"
}
NodeNow (56 days)Before (the 90 days, per 56)AddedConfidenceBasis
visit-reply-lift18.2 qualified responses per 100 written to (4 of 22 matured) · 9 still maturing2.9 hand-raises per 100 fitting visiting companies (3 of 104)— · Worth about +$130 a month—before-after, not proof · Other Startups’ results +4.8 per 100, ■■□□ Early sign, n 2,140
new-leads5 Leads from 31 companies written to2 per 56 days——before-after
new-arr ↑$347, 1 Customer on Pro · Booked: credited, not all caused by this Play$0——before-after · 1 Deal and 1 trial still deciding
net-new-arr · arrcarried from new-arrcarried——carried

Before against after reads one window against the 90 days before it, scaled to 56 days; it is not proof, and Other Startups’ results print beside it. A company counts once 30 days have passed since its first touch.

How it moves it: each fitting company that reads a buying page gets touch 1 a median 19 hours after its scoring visit, opening on a public fact, where before it got nothing unless it wrote first.

Guardrails: before against after: positive-reply-rate on the same Mailboxes, 6.4 % against 5.9 %, and play-sourced-customers, 1 against 0; 0 replies called it tracking.

The Campaign card · sample
{
  "$id": "https://api.sb/leaseline.app/campaigns/account-visits",
  "$type": "Campaign",
  "play": "play:account-visits@1",
  "path": [
    "visit-reply-lift",
    "new-leads",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "visit-reply-lift",
    "unit": "per-100",
    "heldBack": 0,
    "decision": null
  },
  "readout": {
    "value": null,
    "n": 22,
    "maturing": 9,
    "interval": null,
    "readability": "inadmissible",
    "basis": "before-after",
    "pooled": true
  },
  "ledger": {
    "spend": 4,
    "workerCost": 2,
    "hours": 2.6,
    "wonArr": 347,
    "projectedArr": 132,
    "paybackDays": 12
  }
}

Outside benchmark: 2 to 4 verified contacts per resolved company, and about 30 % of business visits resolve to a company (a visitor-identification vendor’s 2026 field data).

Before it · After it. Before it: editorial-seo, paid-search and aeo bring the visits. After it: account-ads reads the company Audience it fills, instant-response answers anyone who writes first, and buying-committee takes a company once 2 or more of its people engage.

Example

Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days), at company grain only. 6,350 visitors came; 1,420 read a buying or evaluation page; 352 network addresses resolved, 241 companies, 84 of them fitting. Read every captured thread at ?threads=all; three follow the tables.

What happened, by optionCompaniesQualified responsesWon (credited, not all caused by this Play)
Write to them · Write as you27 · 44 · 11 on Leaseline Pro at $29 a month (+$347 ARR); 1 Deal, 1 trial open
Ads only · To their CSM21 · 5— · ——
Not now · Let it go6 · 3——
All, against before66 decided, 31 written to5 (4 of 22 matured) · before: 3 hand-raises in 90 days$347 · $0
At 4 a week (the Use it when volume)about 32 in 56 daysbefore-after, not proofOther Startups’ results: +4.8 per 100, ■■□□ Early sign, n 2,140
DayEventWhat happenedYour time
0event_1104 Campaign.createdthe three steps; the dry run fails visit-capture and mailbox-warm25 min
0event_1105 Domain.connectedleaseline.app serves the Site; the notice Version named company lookups15 min
1–13event_1121 Audience.updated, first of 13company Audiences filled while the Mailboxes warmed—
14event_1188 Mailbox.warmedthe first touch sent, to Harbor Row Rentals—
19event_1224 Message.createdthe first qualified reply, Ines at Harbor Row—
31event_1279 Role.updatedpromoted after 20 drafts approved unedited: touches send after a 2-minute hold—
36event_1301 Campaign.pausedsending-stop-loss on sdr@: 4.1 % bounces; POST /{namespace}/mailboxes/{mailbox}/rest for 1 day, resumed6 min
1–56event_1130 Approval.created, first of 2420 drafts in weeks 1 to 4, then 4 as Dana; the match check from the POST /{namespace}/tasks/next log1.6 h · total 2.6 h measured, 3 h asked

Leaseline → Ines Duarte, Harbor Row Rentals, Sep 7, 08:40 · Subject: renewals across 2 new owners · Your news page says Harbor Row took on 2 new owners this summer.¹ At 2 owners, renewal notices usually slip at the hand-off between leasing and accounting.² Leaseline sends every notice 60 days out, per owner. Worth 20 minutes? *Signed with the Role’s disclosure line, with the why-you link.*³

Ines, Sep 12 · “Worth a look. Thursday afternoon?” POST /{namespace}/meetings/book booked it on Priya’s calendar; Harbor Row took Pro on Oct 2 (+$347 ARR).

Harbor Row Rentals, 2026-09-07 · the draft visit-in-copy refused, then the rewrite that sent
- Saw your team checking out our pricing page twice this week, so I thought I’d reach out.
+ Your news page says Harbor Row took on 2 new owners this summer.

Calloway Residential, 2026-10-06 09:10 · 900 units, over the 500-unit line, so the draft went to Dana as Write as you (approval_64, due 17:00). Dana approved it at 11:32, and it sent from dana@ at 08:40 the next morning their time.⁴ The Brief is task_251.

¹ It opens on the company’s own public page. ² Every claim maps to an approved Page. ³ The fixed signature and why-you lines compile from the Role’s Settings. ⁴ Write as you sends only after your OK, on every rung.

Your settings

plays/account-visits.mdx
---
holdout: 0         # at 4 a week, it reads before-after
---
Write only to confirmed property managers at 5 points or more.
Over 500 units, send it as Dana, after her OK.
Never run the person rung.
Text
$ npx startup-builder show plays/account-visits
holdout 0 · the 5-point line · the 500-unit line · person rung off    your file  plays/account-visits.mdx:2,4,5,6 (Ask 2026-08-24)
family demand · process outbound · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences visit-two-touch, visit-two-touch-founder · approval every-send · checks owned-by-a-person, customer-collision, hold, visit-in-copy, approved-pages, notice, market, resolution-stop, decay, mailbox-warm · stops 7 + 2 for the person rung    catalog  play:account-visits@1 (Not live yet, gaps #5)

Every key from the catalog

Key Id What it is
Tactic visit-capture Visit capture: Writes each Site request as a first-party Event, applies the Market’s resolution Setting, and queues lookups only for buying and evaluation Pages. Starts at Sends nothing.
Tactic company-resolve Company resolve: Resolves a network address to an Organization server-side, with a confidence and inferred provenance, and records the visit Events. Starts at Sends nothing.
Tactic person-resolve Person resolve: On the owner-only person rung, matches a US Visitor who accepted the notice to a business profile above the confidence floor, and mints a Prospect. Starts at Sends nothing.
Tactic visit-qualify Visit qualify: Runs the fit gate and the Event stack on a resolved Organization, routes it, assigns the holdout, and mints the Prospect for outreach. Starts at Sends nothing.
Tactic visit-outreach Visit outreach: Writes two touches about a qualified Organization’s public situation, never its Visit, with the grain’s Source line, then parks the Organization. Starts at It does it, you can stop it.
Tactic visit-audience Visit audience: Keeps qualified Organizations, and on the person rung US Prospects, in Audiences with windows for account ads to sync, alike for holdout and treated. Starts at Sends nothing.
Tactic match-check Match check: Each month a human checks 50 person-grain matches and 50 confirmed Organizations, and the wrong rates trip, demote or clear each grain. Starts at You approve each one.
Tactic visit-readout Visit readout: Reads qualified responses from treated Organizations against hand-raises from the holdout, by grain and ICP cell, and stops a grain that shows no lift. Starts at Sends nothing.
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 cold-email-send Cold email send: Sends a passed draft as plain text from an outbound Mailbox with tracking off, records it with its reason and stamp, and handles bounces. Starts at It does it, you can stop it.
Tactic reply-matrix Reply matrix: Labels every outreach reply with one of 11 labels, maps it to one of seven reply kinds, and runs that kind’s move by its deadline. Starts at You approve each one.
Tactic sending-stop-loss Sending stop loss: Reads the Play’s own bounces, replies and seed tests on every send, and rests, pauses or retires a Mailbox, Domain, cell or the Play. Starts at Sends nothing.
Trigger pricing-visit Pricing visit: event on Visit.recorded, window 72h.
Trigger evaluation-visit Evaluation visit: event on Visit.recorded, window 7d.
Trigger repeat-visit Repeat visit: threshold on Visit.recorded, window 7d.
Trigger organization-surge Organization surge: threshold on Visitor.identified, window 7d.
Trigger person-match Person match: threshold on Visitor.identified, window 72h.
Sequence visit-two-touch Visit two touch: 4 steps; it ends on Any reply on any channel; An inbound hand-raise from anyone at the Organization; A bounce; Suppression or a resolution stop at any scope; A booked Meeting; An open Deal; A Customer record; A hold Trigger on the Organization; The person rung’s kill switch, for a person-grain Sequence.
Sequence visit-two-touch-founder Visit two touch founder: 4 steps; it ends on Any reply on any channel; An inbound hand-raise from anyone at the Organization; A bounce; Suppression or a resolution stop at any scope; A booked Meeting; An open Deal; A Customer record; A hold Trigger on the Organization; The Mandate paused or revoked.
Benchmark account-visits-contacts-per-organization Reply rate, 3 or more contacts per Organization against 1 to 2: 3.5–5.1 % (An email-finder vendor’s annual cold email report, 2025 data; correlational, 2025-12-31).
Benchmark account-visits-tracking-off Reply rate with open and click tracking on against off: 4.4–7.4 % (An email-finder vendor’s annual cold email report, 2025 data; correlational, 2025-12-31).
Benchmark account-visits-after-step-one Share of a Sequence’s replies that arrive after step 1: 58.6 % (A lead-generation agency’s response-rate study, 2025 data; steps 2 to 6, 2025-12-31).
Benchmark account-visits-research-wrong-person Share of agent-built research profiles that describe the wrong person: 4 % (A peer-reviewed study of automated spear phishing, 2026, 2026-01-01).

Compiled, not written: edit the Play record account-visits 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.