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
- Summary
- startupbuilder.dev
Be our Content Lead: list Leaseline everywhere small property managers compare software, from our own records only, and fix any listing that drifts. Program applications and Review replies come to me. Show me what’s missing; don’t send.
# Not live yet (gaps #2)
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"directory-listings"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'directory-listings' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"directory-listings"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'directory-listings' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "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"
},
…
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"
}
}application/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 yetPreviewOn 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,
| Try another: the listing | Choice | Reason |
|---|---|---|
| Capterra listing: “$19 a month” | fix-drift | your Pro Price is $29 since Jul 1 |
| A property-management software directory, 8,000 visits a month, no Leaseline listing | push-the-listing | qualified: the buyers your file names read it |
| A comparison blog: “Leaseline has no e-signature.” | ask-for-a-correction | your records show e-signature since March |
| A startup perk portal closes applications Oct 31 | apply-to-a-program | you qualify; its terms bind, so you sign |
| A 2-star G2 Review: “Setup took a week.” | reply-to-a-review | a Review reply goes out in your name, so you approve it |
- 80 min week 1, then 15 a week
- Your time
- Day 6: first listing signup
- First signal
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/
Start it this week
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"}' | Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | None needed: 5 places are enough. | POST /{namespace}/metrics/query |
baseline pass · Not live yet, gaps #8 | None needed: 5 in 90 days is your Before. | POST /{namespace}/metrics/query |
approved-pages fail · Not live yet, gaps #8 | Publish 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 #8 | Staff 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.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
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 number | 1 min | none |
approved-pages · fail (Not live yet) | POST /{namespace}/sites/{site}/publish the facts Page | 20 min | none |
role-unstaffed · warn (gaps #8): no Content Lead or Partnerships seat | POST /{namespace}/roles/{role}/staff, or leave it: applications and Review replies come to you | 0 min | none |
Your number · Before 3 a month · Now 8 listing signups a month · Target 12 a month by Dec 31 · before-after,
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
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| The weekly check finds a field that differs from your records | listing-drift | event on Monitor.checked where a listing differs from the manifest, or fails its install test | 7d | POST /{namespace}/monitors on each listing; it runs weekly |
| A Price, Offer or fact a listing shows changes | manifest-record-changed | event on Fact.changed where record in manifest.sources | every listing within 24 h | PATCH /{namespace}/offers/{id} or PATCH /{namespace}/pages/{id}; the change is the Event |
| A new Review or question lands on a listing | listing-review-posted | event on Review.published where listing in startup.listings | 2d | POST /{namespace}/integrations/connect the review sites |
+ 6 more for status changes, install failures, new places, program deadlines and stale outside facts (?lanes=) |
{
"$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"
}
}
}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:, 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.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Fix drift · Push the listing | It does it, you can stop it | 7 of 7 · 9 of 9 | met on day 14 (the first 10 pushes) | a field shows a value no record held → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Ask a publisher to correct | You approve each one | 2 of 2 | at 5 approved | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Apply to a program · Reply to a Review | To a person, every time | 1 · 3 | never: terms bind, and a reply speaks for you | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/tasks/{task}/claim |
| Ask for Reviews | You approve the first wave | 1 wave, 18 Customers | at 2 waves with no audit gap | the asked set misses an eligible Customer → paused | POST /{namespace}/approvals/{approval}/approve |
| Change the listing rule | You approve each one | 0 merged | never | — | 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 states | To a person, every time | 0 asked | never | — | 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.
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.
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
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Push the listing push-the-listing | a qualified place has no listing, or a shown record changed | Your rule (line 4) | POST /{namespace}/documents/{document}/render the manifest → POST /{namespace}/integrations/{integration}/call → POST /{namespace}/monitors | nobody; a captcha or signed form goes to you | the same |
Fix drift fix-drift | a live field differs from your records | Your rule (line 4) | POST /{namespace}/monitors/{monitor}/check → POST /{namespace}/integrations/{integration}/call the one field | nobody | the same |
Ask a publisher to correct ask-for-a-correction | an outside page states a stale fact | Agent’s call, with its reason | publisher-correction → POST /{namespace}/messages/{message}/schedule | the publisher’s listed contact | the same |
Apply to a program apply-to-a-program | a program you qualify for closes within 14 days | Agent’s call, with its reason | POST /{namespace}/documents → POST /{namespace}/approvals → program-status-check at 10 days | POST /{namespace}/tasks/{task}/assign → you sign, due 1 business day · Take this one | you |
Reply to a Review reply-to-a-review | a new Review or question on a listing | Agent’s call, with its reason | POST /{namespace}/comments drafted → POST /{namespace}/approvals | you approve it, due 1 business day · Take this one | you |
Ask for Reviews ask-for-reviews | every eligible Customer is in the asked set | Your rule (the audit) | POST /{namespace}/messages/{message}/broadcast to the whole eligible set | nobody; held Customers go to their CSM first | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Happy to fix it. What’s the right figure?” | answers with the fact and its source link, quoting only the stale claim | Content Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Send me pricing | “What does Leaseline cost now?” | answers with the Pricing Page’s list Prices, $29 and $79 a month | Content Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “We update comparisons each quarter.” | the follow-up stops; the Decision reopens at their next update | nobody | at once | POST /{namespace}/enrollments/{enrollment}/cancel |
| Wrong person | “Our editor, Sam, handles corrections.” | asks them to forward it; it never writes to an address from their text | Content Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | the follow-up waits for the return date | nobody | the return date | POST /{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 call | you | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Don’t contact us again.” | that publisher is suppressed on every lane | nobody | at once | POST /{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).
[
{
"$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) | Refuses | Fix | Then |
|---|---|---|---|
owned-by-a-person (rule j; Not live yet, gaps #8) | a Review ask to a Customer whose open Deal or Conversation a person holds | Leave 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 pending | Let their CSM reach them first, then ask again once they are healthy. | POST /{namespace}/tasks/next |
customer-ask-cap (gaps #3) | a second open ask to one Customer in a window, from any Play | usage-upsell holds them until Nov 3. | GET /{namespace}/decisions |
claims-resolve (shared) | a listing field, rank or superlative that resolves to no record | Cut 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 it | Leave 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 Customer | Widen 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 signature | You sign it, or the application stays in draft. | POST /{namespace}/agreements/{agreement}/sign |
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.
| Check | Fix | Then |
|---|---|---|
claims-resolve fail | Cut 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.
[
{
"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,
- 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"
}| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
|---|---|---|---|---|---|
listing-signups | 15 signups from 1,120 listing visits | 3 from 410 | — | — | before-after, not proof · Other Startups’ results +6 a month, ■■□□ Early sign, n 640 listings |
new-leads | 15 of 212 new Leads came through a listing | 3 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 · arr | carried from new-arr | carried | — | — | 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.
{
"$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=; three follow the tables.
| What happened, by option | Decisions | Done | Listing signups after |
|---|---|---|---|
| Push the listing · Fix drift | 9 · 7 | 9 live · 7 fixed, median 3 h | 15 in all |
| Ask a publisher to correct · Apply to a program | 2 · 1 | 1 corrected, 1 still deciding · 1 awaiting your signature | — |
| Reply to a Review · Ask for Reviews | 3 · 1 wave | 3 replies you approved · 18 Customers asked, 6 Reviews | — |
| All · the 90 days before, per 56 | 23 | 9 listings, 100 % of fields sourced | 15 · 3 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_1421 Campaign.created | the three steps; the dry run fails approved-pages | 20 min |
| 0 | event_1422 Site.published | the facts Page goes live; 39 of 44 fields sourced, 5 blank | 20 min |
| 1–7 | event_1425 Approval.created, first of 9 | you approved the first 9 pushes; 2 captchas and 1 signed form | 40 min |
| 6 | event_1430 Lead.created | the first listing signup, from a property-management directory | — |
| 14 | event_1437 Role.updated | promoted: pushes and drift fixes send after a 1-hour hold | — |
| 33 | event_1449 Campaign.paused | policy-rejection: one directory rejected 3 screenshots; you swapped them | 15 min |
| 56 | event_1460 Monitor.checked | Capterra shows $19; the fix waits its hold | — |
| 1–56 | event_1428 Task.assigned, first of 4 | 3 Review replies and 1 application; weekly reviews, from the POST /{namespace}/tasks/next log | 45 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.
- 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
---
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. $ 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
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.