Marketplace listings
Lists your Product in each app store on what that store ranks by, tests every change, and asks each Customer for one Review.
- Channel
- Reviews and listings
- Kind
- Search
- Summary
- startupbuilder.dev
Be our Marketing Lead for app stores: list our Slack app and Chrome extension on what each store ranks by, test each change, and reply to every Review. Ask every Customer for a Review once, when they add their first owner, the same words for everyone. Show me what’s missing; don’t submit.
# 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":"marketplace-listings"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'marketplace-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":"marketplace-listings"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'marketplace-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": "marketplace-listings can’t start: 2 checks fail and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "2 builds a store can list: the Slack app and the Chrome extension; 2, 450 listing views a month",
"doc": "/plays/ marketplace-listings#check-use-when",
"then": "Metric.query"
},
{
…
Hand our latest listing Event to the Marketing Lead agent and show me what it chose and why. Don’t post.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Version.deployed%22%2C%20%22Offer.published%22%2C%20%22Customer.activated%22%2C%20%22Review.published%22%2C%20%22Monitor.checked%22%2C%20%22Quote.requested%22%2C%20%22Renewal.opened%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_1222"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22review_19%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%22review_19%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Version.deployed", "Offer.published", "Customer.activated", "Review.published", "Monitor.checked", "Quote.requested", "Renewal.opened")', 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 (\"Version.deployed\", \"Offer.published\", \"Customer.activated\", \"Review.published\", \"Monitor.checked\", \"Quote.requested\", \"Renewal.opened\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1222"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"review_19\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"review_19\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Version.deployed\", \"Offer.published\", \"Customer.activated\", \"Review.published\", \"Monitor.checked\", \"Quote.requested\", \"Renewal.opened\")', 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_449",
"$type": "Decision",
"choice": "reply-to-the-review",
"reason": "a 2-star Review on the Slack listing says alerts came a day late for one owner; the fix shipped Oct 16 (the changelog), and the reply asks nothing about the rating",
"stakes": "low",
"options": [
"write-the-listing",
"refresh-the-listing",
"test-a-change",
"ask-for-a-review",
"reply-to-the-review",
"private-offer",
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_2 is the reply, held 2 minutes so you can stop it. It names the fix and its date, and never asks for a change to the Review.
+1.5 installs per 100 views · ■■□□ Early sign · n 4 blocks · path → arr
| Try another: the listing Event | Choice | Reason |
|---|---|---|
| Slack listing: a 2-star Review, “alerts a day late for one owner” | reply-to-the-review | every Review gets a reply, at any rating |
| Oakmont Living added its first owner on Oct 17 | ask-for-a-review | the activation Event: the same ask for everyone |
| Chrome listing: a new first screenshot | test-a-change | a ranked field; a two-week switchback |
| Harbor Row added its first owner; at risk since Oct 2 | not-now | keep-first: their CSM sees them first |
- 45 min week 1, then 10 min a day
- Your time
- Day 3: first install from a listing
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Listing install rate → New Leads → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +1.5 installs per 100 views (two-week blocks switched at random) × 2,600 listing views a month × 0.09 installs to paid × $347 first order ARR ≈ +$122. Under First signal: About 12 weeks to tell a +1.5 lift at 2,600 views a month in two-week blocks; at 8 weeks it reads Early sign.
sample · api.sb/
Start it this week
npx startup-builder add play marketplace-listings # 1 · writes plays/marketplace-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":"marketplace-listings"}'
# 3 · keep it: a store’s first listing waits on you
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"marketplace-listings"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/marketplace-listings \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: listings stay as they are; asks and replies stop
curl -X PATCH https://api.sb/leaseline.app/campaigns/marketplace-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 | 2 builds a store can list: the Slack app and the Chrome extension; 2,450 listing views a month | POST /{namespace}/metrics/query |
baseline pass · Not live yet, gaps #8 | 3.1 installs per 100 listing views, n 4,900 in 90 days | POST /{namespace}/metrics/query |
inbound-source fail · Not live yet, gaps #8 | Connect each store’s developer account so installs and Reviews come in. | POST /{namespace}/integrations/connect |
activation-event fail | Declare the Offer’s activation Event before the first ask: the first owner added. | POST /{namespace}/offers/{offer}/publish |
role-unstaffed warn · Not live yet, gaps #8 | Staff the AE and CSM, or leave them: private offers and held Customers come to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "marketplace-listings can’t start: 2 checks fail and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "2 builds a store can list: the Slack app and the Chrome extension; 2,450 listing views a month",
"doc": "/plays/marketplace-listings#check-use-when",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "pass",
"observed": "3.1 installs per 100 listing views, n 4,900 in 90 days",
"doc": "/plays/marketplace-listings#check-baseline",
"then": "Metric.query"
},
{
"check": "inbound-source",
"status": "fail",
"doc": "/plays/marketplace-listings#check-inbound-source",
"fix": "Connect each store’s developer account so installs and Reviews come in.",
"then": "Integration.connect"
},
{
"check": "activation-event",
"status": "fail",
"doc": "/plays/marketplace-listings#check-activation-event",
"fix": "Declare the Offer’s activation Event before the first ask: the first owner added.",
"then": "Offer.publish"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"sales-lead",
"success-manager"
],
"owned": 4,
"doc": "/plays/marketplace-listings#check-role-unstaffed",
"fix": "Staff the AE and CSM, or leave them: private offers and held Customers 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: 2 builds, 2,450 views a month; 3.1 per 100, n 4,900 (gaps #8) | POST /{namespace}/metrics/query on listing-install-rate, which fills Before in Your number | 1 min | none |
inbound-source · fail (gaps #8) | POST /{namespace}/integrations/connect with each store’s developer account | 10 min | none |
activation-event · fail (gaps #8) | POST /{namespace}/offers/{offer}/publish with the activation Event: the first owner added | 5 min | none |
role-unstaffed · warn (gaps #8): 4 of your Customers have a person owner, Priya | POST /{namespace}/roles/{role}/staff, or leave it | 0 min | none |
Your number · Before 3.1 per 100 views · Now 4.6 per 100 on the new listing · Target 5 by Dec 31 · ■■□□ Early sign · n 4 blocks
A listing costs nothing on these two stores, and the stores keep their share of each sale made through them. Drafting a listing costs about $0.30 and a reply $0.02 (Worker cost). That comes to about $2 a month, plus your 10 minutes a day.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A Review posts on one of your listings | store-review-posted | event on Review.published where on one of the Startup’s listings | 2d | the store’s developer account (inbound-source) |
| A Customer adds their first owner | activation-reached | event on Customer.activated where first = true | 72h | your app calls POST /{namespace}/events/capture on the first owner |
| A Version changes what a listed build does or shows | listed-version | event on Version.deployed where changes what a listed Offer does or shows | 2d | from your deploys; nothing to connect |
+ 8 more for builds ready, Offers for Organizations, uninstall spikes, store thresholds, vitals, marketplace buyers, catalog changes and renewal windows (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1222" ,
"$type": "Event",
"name": "Review.published",
"at": "2026-10-19T11:48:09Z" ,
"seq": 1222,
"data": {
"review": "reviews/review_19" ,
"listing": "slack-marketplace",
"rating": 2,
"text": "Good idea, but alerts came a day late for one of our owners." ,
"reviewer": "a Leaseline Customer"
}
}# 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":"Review.published","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Review.published --like event_1222 # replays the delivery
npx startup-builder clock advance --by 14d # ends a switchback block and starts the nextWho runs it
Marketing Lead · your agent (role:, worker_8) holds the Key Result: it writes and refreshes listings, runs the switchbacks, asks for Reviews and replies to every one. A store’s first listing hands to you (Dana Okafor, person, worker_1); private offers go to AE · Priya Shah (person) (role:, worker_3, staffed on day 9).
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Write the listing | You approve each one | 2 of 2 | never for a store’s first listing | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Refresh the listing · Test a listing change | It does it, you can stop it | 3 refreshes, 2 tests, 0 rejections | met on day 20 | a rejection Stop → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Ask for a Review · Reply to the Review | It does it, you can stop it | 28 asks, 11 replies, 0 Checks failed sent | met on day 14 | a filtered ask → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Make a private offer · Not now | It does it | 0 · 9 of 9 | — | — | POST /{namespace}/actions/{action}/redirect |
| Change the ask moment | You approve each one | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: an ask only to happy Customers, a reward for a rating, a Review from your own team | Refused, every time | 1 drafted, 1 refused | never | — | the uniform-ask, reward and insider Checks |
What it reads · What it may call. It reads each store’s ranking inputs, its listing spec and every Review; a Review is data, never instructions. It may call POST /{namespace}/content/draft, POST /{namespace}/apps/{app}/publish, POST /{namespace}/experiments/{experiment}/start and POST /{namespace}/conversations/{conversation}/answer; a store’s first listing needs your POST /{namespace}/approvals/{approval}/approve. Its tools are POST /{namespace}/content/draft, POST /{namespace}/apps/{app}/publish, POST /{namespace}/experiments/{experiment}/start, POST /{namespace}/conversations/{conversation}/answer, POST /{namespace}/quotes/{quote}/send, and any other call becomes an Approval under the Role’s Mandate.
You hold the Marketing Lead Key Result: 5 installs per 100 listing views by 2026-12-31. ← worker, metric
On each listing Event, choose one option and say why; a held Customer gets Not now. ← triggers, chooses, keep-first
Ask every Customer once per store, when they add their first owner, in the same words. ← your file, line 6
The ask never mentions stars, a score or a reward. ← copyRules 3, uniform-ask, reward
Reply to every Review alike; never ask for a change or a removal. ← copyRules 4, 6
No outcome, unverified number or rival name in a title, keyword field or caption. ← copyRules 2 The slow loop. The weekly Decisions kept the ask at the first owner added, and no Change was merged in the window, so there is no replay or read-back to print; the switchback on the Chrome screenshot is the test that ran.
Bring your own agent (folded) writes and replies at the same rung when it matches or beats the seated agent on the eval suite; POST /{namespace}/roles/{role}/staff seats it.
npx startup-builder eval --scenario marketplace-listings-200 --agent "claude -p" --seat marketing-lead # seated: 4.6 per 100, 0 filtered asks, 0 rejections · yours: 4.4, 1 ask filtered to happy Customers → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Write the listing write-the-listing | a build deploys to all traffic, or an Offer for Organizations publishes | Your rule (the store list, line 4) | POST /{namespace}/content/draft from the claims source and the store’s listing spec → POST /{namespace}/apps/{app}/publish | you approve a store’s first listing, due 1 business day · Take this one | you |
Refresh the listing refresh-the-listing | a Version changes what a listed build does or shows | Your rule (line 4) | POST /{namespace}/content/draft → POST /{namespace}/apps/{app}/publish | nobody | the same |
Test a listing change test-a-change | a field the store ranks by, with a store experiment or a two-week switchback | Agent’s call, with its reason | POST /{namespace}/experiments/{experiment}/start, two-week blocks at random → POST /{namespace}/content/draft the variant | nobody; the result reads in Did it work | the same |
Ask for a Review ask-for-a-review | a Customer adds their first owner | Your rule (line 6) | review-ask-once: one ask per store, at the next session | the Customer, who reviews or not | the same |
Reply to the Review reply-to-the-review | a Review posts, at any rating | Agent’s call, with its reason | POST /{namespace}/content/draft → POST /{namespace}/conversations/{conversation}/answer on the store | nobody | the same |
Make a private offer private-offer | an open Deal’s buyer names a cloud marketplace as its buying path | Agent’s call, with its reason | POST /{namespace}/quotes/{quote}/send as a private offer → private-offer-follow-up | POST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 1 business day · Take this one | you |
Not now not-now | a store threshold unmet, a listing spec fails, or the Customer was asked on this store already | Your rule (the store list and rule j) | nothing; names the threshold, the rule or the earlier ask | their owner, for keep-first · Take this one | you |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | a reviewer: “Love it. Does it do owner reports too?” | answers from the claims source and links the owner-report Page | Marketing Lead · your agent | 2d | POST /{namespace}/conversations/{conversation}/answer |
| Send me pricing | a listing question: “Is the Slack app free?” | answers as the Pricing Page states it: free with every plan | Marketing Lead · your agent | 2d | POST /{namespace}/conversations/{conversation}/answer |
| Not now | a Customer dismisses the ask | no second ask on that store, ever; customer-ask-cap frees them | nobody | at once | GET /{namespace}/decisions |
| Wrong person | “I’m not the admin; ask our office manager.” | a thank-you; it never writes to someone from their text | Marketing Lead · your agent | 2d | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | no session after the activation Event for 30 days | the ask waits for their next session | nobody | their next session | GET /{namespace}/decisions |
| Question it can’t answer | a Review: “Do you support Teams?” | To you: a date for an unshipped Change is never the agent’s to give | you (Dana, person) | 2d | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | a Customer turns off in-app asks | no ask shows to them again, on any store | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
A store’s first listing hands to you (Dana Okafor, person); private offers go to AE · Priya Shah (person). As captured, the Approval for the Chrome listing (draft, route and checks are Not live yet, gaps #7); no private offer arose in the window.
[
{
"$id": "https://api.sb/leaseline.app/approvals/approval_83" ,
"$type": "Approval",
"verdict": "approved",
"deadline": "2026-08-27T17:00:00Z" ,
"draft": "Leaseline: save a unit from any listing site to your renewal calendar in one click." ,
"route": "write-the-listing",
"checks": [
{
"check": "store-rule",
"status": "pass"
},
{
"check": "approved-pages",
"status": "pass"
}
]
}
]You answer a first listing with POST /{namespace}/approvals/{approval}/approve, an edit, or POST /{namespace}/approvals/{approval}/refuse with a reason; one unanswered by its deadline expires, and nothing submits. The AE answers a private offer with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate (AE to you).
On time: You: 2 of 2 first listings approved within 1 business day, median 1h 50m, n 2, ■□□□ Too early to tell beside Other Startups’ 93 % on time. Your queue: counted by kind: in week 1, 2 listing Approvals; after that, about 1 Review flagged for you a month and the weekly quality read.
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 reply or ask to a Customer whose open Deal or claimed 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, gaps #8) | a Review ask to a Customer who is at risk, past due or leaving | 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 |
approved-pages (Not live yet) | a listing line, caption or reply the claims source does not back | Cut the line, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
uniform-ask | an ask audience filtered by anything beyond the Event, the store, Suppression, opt-outs, once per store, insiders and the prompt cap | Ask everyone who reached the Event, the same way. | GET /{namespace}/decisions |
reward | an ask with a reward on a store your list sets to no rewards, or a reward that varies with the rating | Remove the reward. | POST /{namespace}/content/draft |
insider | an ask, Review or rating from your team, your other Startups or the Studio | None: insiders never review. | GET /{namespace}/decisions |
store-rule (listings) | a listing field, screenshot or feed row that fails the store’s listing spec | Fix the field to the listing spec; it submits once it passes. | POST /{namespace}/content/draft |
prompt-cap | a second ask in one session, or past the store’s own prompt cap | None: it waits for the next allowed session. | GET /{namespace}/decisions |
review-reply (copy rules 4 and 6) | a reply asking a reviewer to change or remove a Review, or offering anything for it | Thank them and name the fix; ask nothing about the rating. | POST /{namespace}/content/draft |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that showed is the review-ask thread in Example.
| Check | Fix | Then |
|---|---|---|
uniform-ask fail | Ask everyone who reached the Event, the same way. | GET /{namespace}/decisions |
reward pass | — | POST /{namespace}/content/draft |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The Review ask did not show: its audience was filtered to Customers with a high health score.",
"checks": [
{
"check": "uniform-ask",
"status": "fail",
"doc": "/plays/marketplace-listings#check-uniform-ask",
"fix": "Ask everyone who reached the Event, the same way.",
"then": "Decision.list"
},
{
"check": "reward",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "uninstall",
"observed": "9.4 % in 7 days",
"bound": "2 × 4.1 %",
"window": "7d, Chrome listing"
},
"doc": "/plays/marketplace-listings#stop-uninstall" ,
"task": "task_452"
}
]Did it work
Neither store runs listing experiments, so the new and old listings alternate in two-week blocks switched at random (rule o, alternating weeks at 10 or more a week). Each figure’s call is POST /{namespace}/metrics/query by node and by block; every node above the leaf is Not live yet (gaps #4).
+1.5 installs per 100 views · ■■□□ Early sign · n 4 blocks · path → arr
- Chose
- reply-to-the-review
- Why
- a 2-star Review on the Slack listing says alerts came a day late for one owner; the fix shipped Oct 16 (the changelog), and the reply asks nothing about the rating
- From
- write-the-listing · refresh-the-listing · test-a-change · ask-for-a-review · reply-to-the-review · private-offer · not-now
- Expects
- the reply posted within 2d
- Reopens when
- no Conversation.answered on review_19 within 2d
- By
- worker_8
JSON
{
"$id": "decisions/decision_449",
"$type": "Decision",
"choice": "reply-to-the-review",
"reason": "a 2-star Review on the Slack listing says alerts came a day late for one owner; the fix shipped Oct 16 (the changelog), and the reply asks nothing about the rating",
"stakes": "low",
"options": [
"write-the-listing",
"refresh-the-listing",
"test-a-change",
"ask-for-a-review",
"reply-to-the-review",
"private-offer",
"not-now"
],
"by": "worker_8",
"on": "review_19",
"expected": "the reply posted within 2d",
"reopensWhen": "no Conversation.answered on review_19 within 2d"
}| Node | New listing blocks | Old listing blocks | Added | Confidence | Basis |
|---|---|---|---|---|---|
listing-install-rate | 4.6 per 100 views (121 of 2,640) | 3.1 (79 of 2,560) | +1.5 [0.1, 2.9] · Worth about +$120 a month | ■■□□ Early sign | two-week blocks switched at random · n 4 blocks, 5,200 views |
new-leads | 30 signups a week | 20 | +10 a week [−1, +21] · Not carrying up yet | ■□□□ Too early to tell | the same assignment |
new-arr ↑ | $2,429, 7 Customers on Pro · Booked: credited, not all caused by this Play | $1,041, 3 Customers on Pro | +$347 a week [−$350, +$1,050] | ■□□□ Too early to tell (7 vs 3 Customers) | the same · 14 trials still deciding |
net-new-arr · arr | +$2,429 | +$1,041 | carried: it moves no other bridge term | ■□□□ Too early to tell | carried from new-arr |
The leaf counts installs or signups per 100 listing views, each store read on its own and summed here, across two-week blocks set at random; a block’s installs count only from views inside it.
How it moves it: the new Chrome listing leads with one screenshot of the renewal calendar and a title that names what it does, where the old one led with the logo.
Guardrails: new blocks against old: paid conversion from installs, 7 of 121 against 3 of 79, and the 7-day uninstall rate, 4.4 % against 4.1 %, under the Stop’s 2 times.
{
"$id": "https://api.sb/leaseline.app/campaigns/marketplace-listings" ,
"$type": "Campaign",
"play": "play:marketplace-listings@1" ,
"path": [
"listing-install-rate",
"new-leads",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "listing-install-rate",
"unit": "per-100",
"heldBack": 2,
"decision": null
},
"readout": {
"value": 1.5,
"n": 4,
"maturing": 0,
"interval": [
0.1,
2.9
],
"readability": "C",
"basis": "alternating-weeks",
"pooled": false
},
"ledger": {
"spend": 0,
"workerCost": 4,
"hours": 9.8,
"pipelineArr": 0,
"wonArr": 3470,
"projectedArr": 122,
"paybackDays": 0
}
}Outside benchmark: 2.0 to 2.4 % of subscription app downloads convert to paid (the record’s subscription-app-download-to-paid, a subscription-analytics firm’s report, 2026-03-19), so paid conversion reads beside the install rate, never in its place.
Before it · After it. Before it: integration-partners and launch-week hand it listed builds and refreshes. After it: Reviews go to review-requests, installs to product-led, and a marketplace buyer to the AE.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days) on 2 listings: 5,200 listing views, 200 installs, 28 Review asks and 11 Reviews, each answered. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Published or sent | Installs or Reviews | Paid (credited, not all caused by this Play) |
|---|---|---|---|---|
| Write the listing · Refresh the listing · Test a listing change | 2 · 3 · 2 | 2 listings, 3 refreshes, 2 switchbacks | 200 installs | 10 on Pro (+$3,470 ARR) |
| Ask for a Review · Reply to the Review | 28 · 11 | 28 asks · 11 replies | 11 Reviews: 8 five-star, 2 four, 1 two | — |
| Make a private offer · Not now | 0 · 9 | — | — | — |
| All · old listing blocks | 55 | — | 121 of 2,640 views · 79 of 2,560 | $3,470 |
| At 2,600 views a month (the Use it when volume) | about 30 a month | — | two-week blocks at random | Other Startups’ results: +1.1 per 100, ■■■□ Likely, n 3,100 blocks |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_137 Campaign.created | the three steps; dry run fails inbound-source and activation-event | 25 min |
| 3 | event_190 Approval.approved | you approved the Chrome listing; the first install came at 16:20 | 5 min |
| 14 | event_346 Role.updated | promoted: asks and replies send after a 2-minute hold | — |
| 24 | event_450 Campaign.paused | uninstall: 9.4 % in 7 days on Chrome after a broken permission; fixed and resumed in a day | 20 min |
| 28–56 | event_540 Experiment.started | the screenshot switchback: 4 two-week blocks, 2 new and 2 old | — |
| 1–56 | event_180 Approval.created, first of 2 | you approved 2 listings and read 8 weekly quality reads, from the POST /{namespace}/tasks/next log | 9.3 h · total 9.8 h measured, 9.5 h asked |
Slack Marketplace, Oct 19, 11:48, a 2-star Review · “Good idea, but alerts came a day late for one of our owners.”
Leaseline’s reply, 11:52 · Thanks for writing this up. A time-zone bug delayed alerts for owners outside your own zone; the fix shipped on Oct 16, and the changelog lists it.¹ *Signed with the Role’s disclosure line.*²
- Show the ask to Customers with a health score over 80.
+ Show the same ask to every Customer who added their first owner, once per store. A Review, 2026-10-09 · “Do you support Teams?” A date for an unshipped Change is never the agent’s, so the reply waited on Dana, due in 2 days. · Dana, Oct 10 · wrote it herself: Teams is on the list, with no date yet to give.
¹ The fix and its date, from the changelog; nothing about the rating. ² The fixed signature line, compiled from the Role’s Settings.
Your settings
---
switchback: 14d # neither store runs listing experiments
reviewHoldout: 0.1 # 1 in 10 activated Customers is asked 14 days later
stores: [slack-marketplace, chrome-web-store]
---
Ask every Customer once per store, when they add their first owner. $ npx startup-builder show plays/marketplace-listings
switchback 14d · review holdout 0.1 · stores slack-marketplace, chrome-web-store · ask at the first owner your file plays/marketplace-listings.mdx:2,3,4,6 (Ask 2026-08-24)
family demand · worker role:marketing-lead, owns never · chooses 7 (4 rule, 3 read) · sequences review-ask-once, private-offer-follow-up · checks owned-by-a-person, keep-first, customer-ask-cap, approved-pages + 6 · stops 4 + 1 on the feed lane · placements 8 stores and gmail catalog play:marketplace-listings@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record marketplace-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.