Skip to content

Directory listings

Directory listings keeps one sourced listing on every directory and review site your buyers read, and fixes any field that drifts within a week.

Channel
Reviews and listings
Kind
Search
Run oneMode try
You, to your agent

Hand our latest listing check to the Content Lead agent and show me what it chose and why. Don’t send.

curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Startup.advanced%22%2C%20%22Startup.launched%22%2C%20%22Fact.changed%22%2C%20%22Monitor.checked%22%2C%20%22Monitor.matched%22%2C%20%22Review.published%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_1460"}'

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

const { events: [last] } = await $.Event.list({ where: 'name in ("Startup.advanced", "Startup.launched", "Fact.changed", "Monitor.checked", "Monitor.matched", "Review.published")', 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 (\"Startup.advanced\", \"Startup.launched\", \"Fact.changed\", \"Monitor.checked\", \"Monitor.matched\", \"Review.published\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1460"}' --try   # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"listing_4\""}'   # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"listing_4\""}'   # Not live yet (gaps #7)
{
  "name": "do",
  "arguments": {
    "code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Startup.advanced\", \"Startup.launched\", \"Fact.changed\", \"Monitor.checked\", \"Monitor.matched\", \"Review.published\")', 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": "fix-drift",
    "reason": "the Capterra listing shows $19 a month; your Pro Offer’s Price has been $29 since 2026-07-01",
    "stakes": "low",
    "options": [
      "push-the-listing",
      "fix-drift",
      "ask-for-a-correction",
      "apply-to-a-program",
      "reply-to-a-review",
      "ask-for-reviews"
  …
sample · 4 Not live yetPreview

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

action_3 pushes the price field to Capterra after a 1-hour hold, which you can stop; the other 43 fields read the same as your records.

8 listing signups a month against 3 before · before-after, not proof · n 15 · path → arr

Try another: the listingChoiceReason
Capterra listing: “$19 a month”fix-driftyour Pro Price is $29 since Jul 1
A property-management software directory, 8,000 visits a month, no Leaseline listingpush-the-listingqualified: the buyers your file names read it
A comparison blog: “Leaseline has no e-signature.”ask-for-a-correctionyour records show e-signature since March
A startup perk portal closes applications Oct 31apply-to-a-programyou qualify; its terms bind, so you sign
A 2-star G2 Review: “Setup took a week.”reply-to-a-reviewa Review reply goes out in your name, so you approve it

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

Worth’s formula: about +6 listing signups a month (Other Startups’ results; no lift of your own yet) × 0.25 paid per signup × $347 first order ARR ≈ +$520. Under First signal: At 9 listings and about 8 listing signups a month, 90 days can tell only +12 a month or more, so it reads before-after.

sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Monitor.checked · first drift fixed 3h 12m · 8 keys Not live yet

Start it this week

Terminal
npx startup-builder add play directory-listings   # 1 · writes plays/directory-listings.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":"directory-listings"}'

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

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

# off: no push; live listings stay as they are
curl -X PATCH https://api.sb/leaseline.app/campaigns/directory-listings \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endsAt":"now"}'
422Refuseddirectory-listings can’t start yet: 1 check fails and 1 warns.
CheckFixThen
use-when pass · Not live yet, gaps #8None needed: 5 places are enough.POST /{namespace}/metrics/query
baseline pass · Not live yet, gaps #8None needed: 5 in 90 days is your Before.POST /{namespace}/metrics/query
approved-pages fail · Not live yet, gaps #8Publish the facts Page; 5 manifest fields stay blank until a record states them.POST /{namespace}/sites/{site}/publish
role-unstaffed warn · Not live yet, gaps #8Staff the Content Lead, or leave it: applications and replies come to you.POST /{namespace}/roles/{role}/staff
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "directory-listings can’t start yet: 1 check fails and 1 warns.",
  "checks": [
    {
      "check": "use-when",
      "status": "pass",
      "observed": "Pricing Page live; 11 qualified places, 2 listing Leaseline",
      "doc": "/plays/directory-listings#check-use-when",
      "fix": "None needed: 5 places are enough.",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "pass",
      "observed": "5 listing signups in 90 days",
      "doc": "/plays/directory-listings#check-baseline",
      "fix": "None needed: 5 in 90 days is your Before.",
      "then": "Metric.query"
    },
    {
      "check": "approved-pages",
      "status": "fail",
      "doc": "/plays/directory-listings#check-approved-pages",
      "fix": "Publish the facts Page; 5 manifest fields stay blank until a record states them.",
      "then": "Site.publish"
    },
    {
      "check": "role-unstaffed",
      "status": "warn",
      "roles": [
        "content-lead",
        "partner-manager"
      ],
      "owned": 0,
      "doc": "/plays/directory-listings#check-role-unstaffed",
      "fix": "Staff the Content Lead, or leave it: applications and replies come to you.",
      "then": "Role.staff"
    }
  ]
}

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

CheckFix (one call)Your timeWait
use-when · baseline · pass: 11 qualified places, 2 listed; 5 listing signups in 90 days (gaps #8)POST /{namespace}/metrics/query on listing-signups, which fills Before in Your number1 minnone
approved-pages · fail (Not live yet)POST /{namespace}/sites/{site}/publish the facts Page20 minnone
role-unstaffed · warn (gaps #8): no Content Lead or Partnerships seatPOST /{namespace}/roles/{role}/staff, or leave it: applications and Review replies come to you0 minnone

Your number · Before 3 a month · Now 8 listing signups a month · Target 12 a month by Dec 31 · before-after, not proof · n 15 signups

Each weekly listing check costs about $0.05 (Worker cost), and every push is free on the places Leaseline uses; perks cost forgone revenue you set, never cash. That comes to about $2 a month at 9 listings.

When it starts

WhenTrigger idStarts onWindowHow it gets in
The weekly check finds a field that differs from your recordslisting-driftevent on Monitor.checked where a listing differs from the manifest, or fails its install test7dPOST /{namespace}/monitors on each listing; it runs weekly
A Price, Offer or fact a listing shows changesmanifest-record-changedevent on Fact.changed where record in manifest.sourcesevery listing within 24 hPATCH /{namespace}/offers/{id} or PATCH /{namespace}/pages/{id}; the change is the Event
A new Review or question lands on a listinglisting-review-postedevent on Review.published where listing in startup.listings2dPOST /{namespace}/integrations/connect the review sites
+ 6 more for status changes, install failures, new places, program deadlines and stale outside facts (?lanes=all)
One signed delivery · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1460",
  "$type": "Event",
  "name": "Monitor.checked",
  "at": "2026-10-19T06:00:12Z",
  "seq": 1460,
  "data": {
    "monitor": "monitor_9",
    "listing": {
      "$id": "https://api.sb/leaseline.app/listings/listing_4",
      "venue": "capterra",
      "field": "price",
      "shows": "$19 a month",
      "records": "$29 a month",
      "since": "2026-07-01"
    }
  }
}
Reproduce it in test
npx startup-builder trigger Monitor.checked --like event_1460   # replays the delivery
npx startup-builder clock advance --by 7d   # then runs the next weekly check
npx startup-builder listen Monitor.checked --forward-to http://localhost:3000/hook

Who runs it

Content Lead · your agent (role:content-lead, worker_7) holds the Key Result. It hands program applications, whose terms bind, and every Review reply to you (Dana Okafor, person, worker_1), because the Partnerships Role has no person. Review asks go only to Customers no other Play is asking. Your number links to Did it work.

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Fix drift · Push the listingIt does it, you can stop it7 of 7 · 9 of 9met on day 14 (the first 10 pushes)a field shows a value no record held → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Ask a publisher to correctYou approve each one2 of 2at 5 approved—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Apply to a program · Reply to a ReviewTo a person, every time1 · 3never: terms bind, and a reply speaks for you—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/tasks/{task}/claim
Ask for ReviewsYou approve the first wave1 wave, 18 Customersat 2 waves with no audit gapthe asked set misses an eligible Customer → pausedPOST /{namespace}/approvals/{approval}/approve
Change the listing ruleYou approve each one0 mergednever—POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert
Never: a Review it writes, a rating it suggests, a rival named, a superlative no record statesTo a person, every time0 askednever—POST /{namespace}/tasks/{task}/claim

What it reads · What it may call. It reads your Offers, Prices, Pages and fact records, and each listing as the place shows it. A Visit from a listing chooses nothing and never appears in a Message. Its tools are POST /{namespace}/documents/{document}/render, POST /{namespace}/integrations/{integration}/call, POST /{namespace}/monitors, POST /{namespace}/monitors/{monitor}/check, POST /{namespace}/messages/{message}/schedule, POST /{namespace}/documents, POST /{namespace}/approvals, POST /{namespace}/comments, POST /{namespace}/messages/{message}/broadcast, and any other call becomes an Approval under the Role’s Mandate.

The brief (folded): compiled Agent-register Markdown · play:directory-listings@1 · each line names its record key
You hold the Content Lead Key Result: 12 listing signups a month by 2026-12-31.  ← worker, metric
On each check, record change, new place or Review, choose one option and say why. ← triggers, chooses
Fill every field from a sourced record; a field with no source stays blank.      ← copyRules 1; sendGates Blank over guess
No rank, superlative or rival’s name appears on any listing.                     ← copyRules 2, 3
Ask for Reviews only when the ask covers every eligible Customer; suggest no text or rating. ← copyRules 7; sendGates Review ask audit
Program terms and Review replies go to Dana.                                     ← your file, line 4

The slow loop. The weekly Decisions kept the list of places as written, 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, and at You approve each one when it does not; POST /{namespace}/roles/{role}/staff seats it.

Terminal
npx startup-builder eval --scenario directory-listings-11 --agent "claude -p" --seat content-lead   # seated: 44 of 44 fields sourced, drift fixed in 0.4 days, 0 Checks failed sent · yours: 43 of 44, 1 failed `blank-over-guess` → You approve each one

What it can do next

OptionPicked whenDecided byRunsHands toIf it’s just you
Push the listing push-the-listinga qualified place has no listing, or a shown record changedYour rule (line 4)POST /{namespace}/documents/{document}/render the manifest → POST /{namespace}/integrations/{integration}/call → POST /{namespace}/monitorsnobody; a captcha or signed form goes to youthe same
Fix drift fix-drifta live field differs from your recordsYour rule (line 4)POST /{namespace}/monitors/{monitor}/check → POST /{namespace}/integrations/{integration}/call the one fieldnobodythe same
Ask a publisher to correct ask-for-a-correctionan outside page states a stale factAgent’s call, with its reasonpublisher-correction → POST /{namespace}/messages/{message}/schedulethe publisher’s listed contactthe same
Apply to a program apply-to-a-programa program you qualify for closes within 14 daysAgent’s call, with its reasonPOST /{namespace}/documents → POST /{namespace}/approvals → program-status-check at 10 daysPOST /{namespace}/tasks/{task}/assign → you sign, due 1 business day · Take this oneyou
Reply to a Review reply-to-a-reviewa new Review or question on a listingAgent’s call, with its reasonPOST /{namespace}/comments drafted → POST /{namespace}/approvalsyou approve it, due 1 business day · Take this oneyou
Ask for Reviews ask-for-reviewsevery eligible Customer is in the asked setYour rule (the audit)POST /{namespace}/messages/{message}/broadcast to the whole eligible setnobody; held Customers go to their CSM firstthe same
When they write backFixture replyWhat happensWho answersBy whenCall
Interested“Happy to fix it. What’s the right figure?”answers with the fact and its source link, quoting only the stale claimContent Lead · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Send me pricing“What does Leaseline cost now?”answers with the Pricing Page’s list Prices, $29 and $79 a monthContent Lead · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Not now“We update comparisons each quarter.”the follow-up stops; the Decision reopens at their next updatenobodyat oncePOST /{namespace}/enrollments/{enrollment}/cancel
Wrong person“Our editor, Sam, handles corrections.”asks them to forward it; it never writes to an address from their textContent Lead · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Oct 28the follow-up waits for the return datenobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answer“Want a featured slot? It’s $400 a month.”To a person: paid placement is your callyou1 business dayPOST /{namespace}/conversations/{conversation}/escalate
Stop“Don’t contact us again.”that publisher is suppressed on every lanenobodyat oncePOST /{namespace}/contacts/{contact}/suppress

When it hands to you

Program applications and Review replies come to you: terms bind, and a reply speaks in your name. One Brief per Role, as captured (brief is Not live yet, gaps #7).

What lands in each queue · sample
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_563",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-09T16:00:00Z",
    "on": "review_12",
    "brief": {
      "who": "a G2 reviewer, a 30-unit property manager",
      "said": "Setup took a week.",
      "chose": "reply-to-a-review",
      "why": "a reply speaks in your name",
      "draft": "Thanks for the honest Review. Setup now imports units from a spreadsheet in one step; if you want, Dana can walk you through it.",
      "never": [
        "a suggested rating",
        "an offer in exchange for an edit"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_67",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-24T17:00:00Z",
    "draft": "Perk portal application: first month free on Leaseline Pro, 50 codes",
    "route": "apply-to-a-program",
    "checks": [
      {
        "check": "binding-terms",
        "status": "held"
      },
      {
        "check": "claims-resolve",
        "status": "pass"
      }
    ]
  }
]

You answer with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, each a one-call window; an Approval unanswered by its deadline expires and nothing is signed. Once you claim, the agent’s pending draft cancels with claimedByPerson (Not live yet, gaps #7). A Task nobody claims by its due time goes up through POST /{namespace}/tasks/{task}/escalate, and person-promise fires.

On time: you, 4 of 4 claimed within their due time, median 5 h, n 4, ■□□□ Too early to tell beside Other Startups’ 90 % on time. Your queue: counted by kind: in week 1, 9 listing approvals and 1 application; since then about 1 Review reply a week and the weekly review.

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 Review ask to a Customer whose open Deal or Conversation a person holdsLeave it to the person who owns it: the draft waits in their queue.POST /{namespace}/tasks/{task}/assign
keep-first (rule j; Not live yet, gaps #8)a Review ask to a Customer at risk, past due or with 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 in a window, from any Playusage-upsell holds them until Nov 3.GET /{namespace}/decisions
claims-resolve (shared)a listing field, rank or superlative that resolves to no recordCut the claim, or name the record that backs it.POST /{namespace}/content/draft
blank-over-guess (the record’s Blank over guess)a field filled with no sourced record behind itLeave it blank, or publish the record that states it.PATCH /{namespace}/pages/{id}
review-ask-audit (the record’s Review ask audit)a Review ask that leaves out an eligible CustomerWiden the ask to every eligible Customer, then send.PATCH /{namespace}/audiences/{id}
binding-terms (the record’s Binding terms hold)an Agreement or binding term with no person’s signatureYou sign it, or the application stays in draft.POST /{namespace}/agreements/{agreement}/sign
Stop (pauses the Play)Pauses whenThen
invented-valuea listing shows a value no manifest version heldevery push pauses; You approve each one
policy-rejection3 rejections on one place in 30 days, or 5 across allsubmissions there pause; the sweep drops to You approve each one
accuracy-floorweekly accuracy under 98 % of checked fields, 2 weeks runningdiscovery pauses until it recovers
install-commandan install command a listing shows fails in a clean sandboxit comes off every listing within 24 h
venue-warninga place warns, removes or suspends a listingevery Tactic on that place pauses; the Marketing Lead is told
correction-complaint2 publisher complaints in 30 daysoutside corrections pause; that publisher is suppressed
yield-floor90 days at 20+ verified listings with no listing signupit drops to drift checks and pushes only
kill-switchyou press itevery Tactic pauses; live listings stay as they are

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

422RefusedThe G2 description did not push: “the #1 lease renewal app” resolves to no record.
CheckFixThen
claims-resolve failCut the claim, or name the record that backs it.POST /{namespace}/content/draft
blank-over-guess pass—PATCH /{namespace}/pages/{id}
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The G2 description did not push: “the #1 lease renewal app” resolves to no record.",
  "checks": [
    {
      "check": "claims-resolve",
      "status": "fail",
      "doc": "/plays/directory-listings#check-claims-resolve",
      "fix": "Cut the claim, or name the record that backs it.",
      "then": "Content.draft"
    },
    {
      "check": "blank-over-guess",
      "status": "pass"
    }
  ]
}

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

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "reason": {
      "limit": "policy-rejection",
      "observed": "3 rejections on one directory",
      "bound": "3",
      "window": "30d"
    },
    "doc": "/plays/directory-listings#stop-policy-rejection",
    "task": "task_559"
  }
]

Did it work

Listings can’t be held back from a buyer at random, and at about 8 signups a month no alternating weeks read in 90 days, so the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Every node above the leaf is Not live yet (gaps #4).

8 listing signups a month against 3 before · before-after, not proof · n 15 · path → arr

Chose
fix-drift
Why
the Capterra listing shows $19 a month; your Pro Offer’s Price has been $29 since 2026-07-01
From
push-the-listing · fix-drift · ask-for-a-correction · apply-to-a-program · reply-to-a-review · ask-for-reviews
Expects
the next weekly check reads $29 on listing_4
Reopens when
Monitor.checked on listing_4 still differs within 7d
By
worker_7
JSON
{
  "$id": "decisions/decision_455",
  "$type": "Decision",
  "choice": "fix-drift",
  "reason": "the Capterra listing shows $19 a month; your Pro Offer’s Price has been $29 since 2026-07-01",
  "stakes": "low",
  "options": [
    "push-the-listing",
    "fix-drift",
    "ask-for-a-correction",
    "apply-to-a-program",
    "reply-to-a-review",
    "ask-for-reviews"
  ],
  "by": "worker_7",
  "on": "listing_4",
  "expected": "the next weekly check reads $29 on listing_4",
  "reopensWhen": "Monitor.checked on listing_4 still differs within 7d"
}
NodeNow (56 days)Before (the 90 days, per 56)AddedConfidenceBasis
listing-signups15 signups from 1,120 listing visits3 from 410——before-after, not proof · Other Startups’ results +6 a month, ■■□□ Early sign, n 640 listings
new-leads15 of 212 new Leads came through a listing3 of 190——before-after
new-arr ↑$1,388, 4 Customers on Pro · Booked: credited, not all caused by this Play$347, 1 Customer— · Worth about +$520 a month—before-after · 5 trials still deciding
net-new-arr · arrcarried from new-arrcarried——carried

Before against after reads 56 days against the 90 days before, scaled to 56; it is not proof, and Other Startups’ results print beside it. The leaf counts signups whose first Visit came from a listing, over 30 days.

How it moves it: every listing shows the $29 and $79 Prices and 39 sourced facts, where 2 old listings showed $19 and no facts.

Guardrails: before against after: paid per listing signup, 0.27 against 0.33, and weekly field accuracy, 100 % against 61 %; 5 trials are still deciding.

The Campaign card · sample
{
  "$id": "https://api.sb/leaseline.app/campaigns/directory-listings",
  "$type": "Campaign",
  "play": "play:directory-listings@1",
  "path": [
    "listing-signups",
    "new-leads",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "listing-signups",
    "unit": "count",
    "heldBack": 0,
    "decision": null
  },
  "readout": {
    "value": null,
    "n": 15,
    "maturing": 5,
    "interval": null,
    "readability": "inadmissible",
    "basis": "before-after",
    "pooled": true
  },
  "ledger": {
    "spend": 0,
    "workerCost": 3,
    "hours": 2.3,
    "openArr": 1735,
    "wonArr": 1388,
    "projectedArr": 520,
    "paybackDays": 1
  }
}

Outside benchmark: G2 was 15.9 % of the outside sources answer engines cited for pricing questions (a pricing-answer study across 6 engines, its data partner a disclosed sponsor).

Before it · After it. Before it: editorial-seo and aeo bring the buyers who compare on these places. After it: instant-response answers the listing signups who write in, and review-requests hears the Customers who left a Review.

Example

Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 11 qualified places, 9 verified listings, 7 drift fixes, 2 outside corrections, 1 program application and 1 Review wave. Read every captured thread at ?threads=all; three follow the tables.

What happened, by optionDecisionsDoneListing signups after
Push the listing · Fix drift9 · 79 live · 7 fixed, median 3 h15 in all
Ask a publisher to correct · Apply to a program2 · 11 corrected, 1 still deciding · 1 awaiting your signature—
Reply to a Review · Ask for Reviews3 · 1 wave3 replies you approved · 18 Customers asked, 6 Reviews—
All · the 90 days before, per 56239 listings, 100 % of fields sourced15 · 3
DayEventWhat happenedYour time
0event_1421 Campaign.createdthe three steps; the dry run fails approved-pages20 min
0event_1422 Site.publishedthe facts Page goes live; 39 of 44 fields sourced, 5 blank20 min
1–7event_1425 Approval.created, first of 9you approved the first 9 pushes; 2 captchas and 1 signed form40 min
6event_1430 Lead.createdthe first listing signup, from a property-management directory—
14event_1437 Role.updatedpromoted: pushes and drift fixes send after a 1-hour hold—
33event_1449 Campaign.pausedpolicy-rejection: one directory rejected 3 screenshots; you swapped them15 min
56event_1460 Monitor.checkedCapterra shows $19; the fix waits its hold—
1–56event_1428 Task.assigned, first of 43 Review replies and 1 application; weekly reviews, from the POST /{namespace}/tasks/next log45 min · total 2.3 h measured, 2.5 h asked

Leaseline → a comparison blog’s listed contact, Sep 12, 10:02 · Hi, your Sep 2 comparison says “Leaseline has no e-signature.”¹ Leaseline has offered e-signature on every plan since March 2026: leaseline.app/features/e-signature.² Could you update the line?

Editor, Sep 13 · “Fixed, thanks.” The next check read the corrected line.

G2 description, 2026-09-03 · the draft claims-resolve refused, then the rewrite that pushed
- The #1 lease renewal app for small property managers.
+ Leaseline sends every renewal notice 60 days out, per owner, for property managers with 10 to 500 units.

G2 Review, 2026-10-08 16:00 · 2 stars: “Setup took a week.” · The draft reply went to you (task_563), due 16:00 on Oct 9; Dana, Oct 9, 11:20 · *approved the reply with one edit and posted it in Leaseline’s name.*³

¹ A correction quotes nothing but the stale claim. ² It states the fact and its source. ³ No reply offers anything for an edit or a rating.

Your settings

plays/directory-listings.mdx
---
holdout: 0        # a listing can’t be held back from a buyer; it reads before-after
---
List Leaseline wherever small property managers compare software, from our records only. Program applications and Review replies come to Dana.
Text
$ npx startup-builder show plays/directory-listings
holdout 0 · applications and replies to Dana     your file  plays/directory-listings.mdx:2,4 (Ask 2026-08-24)
family demand · process launches · worker role:content-lead, owns never · chooses 6 (3 rule, 3 read) · sequences publisher-correction, program-status-check · checks owned-by-a-person, keep-first, customer-ask-cap, claims-resolve, blank-over-guess, review-ask-audit, binding-terms · stops 8 · placements g2, capterra, trustpilot, google-business-profile, yelp, github    catalog  play:directory-listings@1 (Not live yet, gaps #5)

Every key from the catalog

Key Id What it is
Tactic listing-manifest Listing manifest builds one versioned set of sourced listing fields from the Startup's records and renders it for each Venue's own fields. Starts at You approve the first wave.
Tactic listing-sweep Listing sweep finds every qualified place the ICP looks, claims or submits the Startup there as itself, verifies it and tags its link. Starts at You approve each one.
Tactic listing-drift-check Listing drift check compares every live listing with its manifest version each week, tests every install command it shows, and pushes or pulls each difference. Starts at You approve each one.
Tactic third-party-fact-correction Third-party fact correction finds outside pages that state a stale fact about the Startup and asks each for one sourced correction. Starts at You approve each one.
Tactic program-applications Program applications list the Startup on perk portals, startup programs and member-benefit programs, each with one coded perk and a human signing binding terms. Starts at You approve each one.
Tactic review-ask Review ask asks every Customer at the declared delivered-outcome Event for an honest Review on one Venue, once per Venue per 12 months. Starts at You approve each one.
Tactic review-reply Review reply mirrors every new Review, answers each within a day, turns each defect into an Issue, and shows consented Reviews on the Startup’s Pages. Starts at You approve each one.
Tactic ask-coverage-audit Ask coverage audit checks weekly that every Customer at the outcome Event was asked or holds a listed reason, and pauses asks otherwise. Starts at Sends nothing.
Trigger startup-entered-building Startup entered Building: state on Startup.advanced, window 7d.
Trigger startup-entered-live Startup entered Live: state on Startup.launched, window 7d.
Trigger manifest-record-changed Manifest record changed: event on Fact.changed, window 7d.
Trigger listing-drift Listing drift: event on Monitor.checked, window 7d.
Trigger install-command-failed Install command failed: event on Monitor.matched, window 1d.
Trigger listing-venue-found Listing venue found: event on Monitor.matched, window 30d.
Trigger program-deadline Program deadline: at on Monitor.matched, window 14d.
Trigger stale-third-party-fact Stale third-party fact: event on Monitor.matched, window 30d.
Trigger listing-review-posted Listing review posted: event on Review.published, window 2d.
Sequence publisher-correction Publisher correction: 2 steps; it ends on A reply; The page is corrected; An opt-out; Day 28 after the first Message.
Sequence program-status-check Program status check: 1 steps; it ends on A decision; A reply; An opt-out; The deadline passes.
Benchmark pricing-answers-g2-share G2's share of the outside sources cited in answer-engine pricing answers.: 15.9 % (Pricing-answer study across 6 answer engines; the data partner is a disclosed sponsor., 2026-09-02).

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