Skip to content

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

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

On 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 EventChoiceReason
Slack listing: a 2-star Review, “alerts a day late for one owner”reply-to-the-reviewevery Review gets a reply, at any rating
Oakmont Living added its first owner on Oct 17ask-for-a-reviewthe activation Event: the same ask for everyone
Chrome listing: a new first screenshottest-a-changea ranked field; a two-week switchback
Harbor Row added its first owner; at risk since Oct 2not-nowkeep-first: their CSM sees them first

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/leaseline.app · 41 Customers at 2026-10-19 · on Review.published · first reply draft 4m 05s · 7 keys Not live yet

Start it this week

Terminal
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"}'
422Refusedmarketplace-listings can’t start: 2 checks fail and 1 warns.
CheckFixThen
use-when pass · Not live yet, gaps #82 builds a store can list: the Slack app and the Chrome extension; 2,450 listing views a monthPOST /{namespace}/metrics/query
baseline pass · Not live yet, gaps #83.1 installs per 100 listing views, n 4,900 in 90 daysPOST /{namespace}/metrics/query
inbound-source fail · Not live yet, gaps #8Connect each store’s developer account so installs and Reviews come in.POST /{namespace}/integrations/connect
activation-event failDeclare 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 #8Staff 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.

CheckFix (one call)Your timeWait
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 number1 minnone
inbound-source · fail (gaps #8)POST /{namespace}/integrations/connect with each store’s developer account10 minnone
activation-event · fail (gaps #8)POST /{namespace}/offers/{offer}/publish with the activation Event: the first owner added5 minnone
role-unstaffed · warn (gaps #8): 4 of your Customers have a person owner, PriyaPOST /{namespace}/roles/{role}/staff, or leave it0 minnone

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

WhenTrigger idStarts onWindowHow it gets in
A Review posts on one of your listingsstore-review-postedevent on Review.published where on one of the Startup’s listings2dthe store’s developer account (inbound-source)
A Customer adds their first owneractivation-reachedevent on Customer.activated where first = true72hyour app calls POST /{namespace}/events/capture on the first owner
A Version changes what a listed build does or showslisted-versionevent on Version.deployed where changes what a listed Offer does or shows2dfrom 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=all)
One signed delivery · StartupBuilder-Signature
{
  "$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"
  }
}
Reproduce it in test
# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":"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 next

Who runs it

Marketing Lead · your agent (role:marketing-lead, 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:sales-lead, worker_3, staffed on day 9).

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Write the listingYou approve each one2 of 2never for a store’s first listing—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Refresh the listing · Test a listing changeIt does it, you can stop it3 refreshes, 2 tests, 0 rejectionsmet on day 20a rejection Stop → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Ask for a Review · Reply to the ReviewIt does it, you can stop it28 asks, 11 replies, 0 Checks failed sentmet on day 14a filtered ask → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Make a private offer · Not nowIt does it0 · 9 of 9——POST /{namespace}/actions/{action}/redirect
Change the ask momentYou approve each one0 mergednever—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 teamRefused, every time1 drafted, 1 refusednever—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.

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

Terminal
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

OptionPicked whenDecided byRunsHands toIf it’s just you
Write the listing write-the-listinga build deploys to all traffic, or an Offer for Organizations publishesYour rule (the store list, line 4)POST /{namespace}/content/draft from the claims source and the store’s listing spec → POST /{namespace}/apps/{app}/publishyou approve a store’s first listing, due 1 business day · Take this oneyou
Refresh the listing refresh-the-listinga Version changes what a listed build does or showsYour rule (line 4)POST /{namespace}/content/draft → POST /{namespace}/apps/{app}/publishnobodythe same
Test a listing change test-a-changea field the store ranks by, with a store experiment or a two-week switchbackAgent’s call, with its reasonPOST /{namespace}/experiments/{experiment}/start, two-week blocks at random → POST /{namespace}/content/draft the variantnobody; the result reads in Did it workthe same
Ask for a Review ask-for-a-reviewa Customer adds their first ownerYour rule (line 6)review-ask-once: one ask per store, at the next sessionthe Customer, who reviews or notthe same
Reply to the Review reply-to-the-reviewa Review posts, at any ratingAgent’s call, with its reasonPOST /{namespace}/content/draft → POST /{namespace}/conversations/{conversation}/answer on the storenobodythe same
Make a private offer private-offeran open Deal’s buyer names a cloud marketplace as its buying pathAgent’s call, with its reasonPOST /{namespace}/quotes/{quote}/send as a private offer → private-offer-follow-upPOST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 1 business day · Take this oneyou
Not now not-nowa store threshold unmet, a listing spec fails, or the Customer was asked on this store alreadyYour rule (the store list and rule j)nothing; names the threshold, the rule or the earlier asktheir owner, for keep-first · Take this oneyou
When they write backFixture replyWhat happensWho answersBy whenCall
Interesteda reviewer: “Love it. Does it do owner reports too?”answers from the claims source and links the owner-report PageMarketing Lead · your agent2dPOST /{namespace}/conversations/{conversation}/answer
Send me pricinga listing question: “Is the Slack app free?”answers as the Pricing Page states it: free with every planMarketing Lead · your agent2dPOST /{namespace}/conversations/{conversation}/answer
Not nowa Customer dismisses the askno second ask on that store, ever; customer-ask-cap frees themnobodyat onceGET /{namespace}/decisions
Wrong person“I’m not the admin; ask our office manager.”a thank-you; it never writes to someone from their textMarketing Lead · your agent2dPOST /{namespace}/conversations/{conversation}/answer
Out of officeno session after the activation Event for 30 daysthe ask waits for their next sessionnobodytheir next sessionGET /{namespace}/decisions
Question it can’t answera Review: “Do you support Teams?”To you: a date for an unshipped Change is never the agent’s to giveyou (Dana, person)2dPOST /{namespace}/conversations/{conversation}/escalate
Stopa Customer turns off in-app asksno ask shows to them again, on any storenobodyat oncePOST /{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.

What lands in each queue · sample
[
  {
    "$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)RefusesFixThen
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 holdsLeave 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 leavingLet 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
approved-pages (Not live yet)a listing line, caption or reply the claims source does not backCut the line, or publish the Page that says it.POST /{namespace}/sites/{site}/publish
uniform-askan ask audience filtered by anything beyond the Event, the store, Suppression, opt-outs, once per store, insiders and the prompt capAsk everyone who reached the Event, the same way.GET /{namespace}/decisions
rewardan ask with a reward on a store your list sets to no rewards, or a reward that varies with the ratingRemove the reward.POST /{namespace}/content/draft
insideran ask, Review or rating from your team, your other Startups or the StudioNone: insiders never review.GET /{namespace}/decisions
store-rule (listings)a listing field, screenshot or feed row that fails the store’s listing specFix the field to the listing spec; it submits once it passes.POST /{namespace}/content/draft
prompt-capa second ask in one session, or past the store’s own prompt capNone: 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 itThank them and name the fix; ask nothing about the rating.POST /{namespace}/content/draft
Stop (pauses the Play)Pauses whenThen
rejection (listings)2 store rejections in 30 dayslisting writes to that store stop until the Marketing Lead, so you, clears it
uninstall (listings)a 7-day uninstall rate over twice the listing’s baselinepaid and Portfolio install sources to it pause
vitals (listings)a store performance limit failed in 2 weekly reads runningnew install sources pause until a fix deploys
kill-switchyou press itevery Tactic pauses at once; listings stay up
+ 1 more for the feed lane: a Price that differs from the live Site leaves the feed within 1 hour (?lanes=all)

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.

422RefusedThe Review ask did not show: its audience was filtered to Customers with a high health score.
CheckFixThen
uniform-ask failAsk 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.

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "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"
}
NodeNew listing blocksOld listing blocksAddedConfidenceBasis
listing-install-rate4.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 signtwo-week blocks switched at random · n 4 blocks, 5,200 views
new-leads30 signups a week20+10 a week [−1, +21] · Not carrying up yet■□□□ Too early to tellthe 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,041carried: it moves no other bridge term■□□□ Too early to tellcarried 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.

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

What happened, by optionDecisionsPublished or sentInstalls or ReviewsPaid (credited, not all caused by this Play)
Write the listing · Refresh the listing · Test a listing change2 · 3 · 22 listings, 3 refreshes, 2 switchbacks200 installs10 on Pro (+$3,470 ARR)
Ask for a Review · Reply to the Review28 · 1128 asks · 11 replies11 Reviews: 8 five-star, 2 four, 1 two—
Make a private offer · Not now0 · 9———
All · old listing blocks55—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 randomOther Startups’ results: +1.1 per 100, ■■■□ Likely, n 3,100 blocks
DayEventWhat happenedYour time
0event_137 Campaign.createdthe three steps; dry run fails inbound-source and activation-event25 min
3event_190 Approval.approvedyou approved the Chrome listing; the first install came at 16:205 min
14event_346 Role.updatedpromoted: asks and replies send after a 2-minute hold—
24event_450 Campaign.pauseduninstall: 9.4 % in 7 days on Chrome after a broken permission; fixed and resumed in a day20 min
28–56event_540 Experiment.startedthe screenshot switchback: 4 two-week blocks, 2 new and 2 old—
1–56event_180 Approval.created, first of 2you approved 2 listings and read 8 weekly quality reads, from the POST /{namespace}/tasks/next log9.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.*²

The Review ask, 2026-09-05 · the audience uniform-ask refused, then the ask that showed
- 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

plays/marketplace-listings.mdx
---
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.
Text
$ 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

Key Id What it is
Tactic store-listing-upkeep Store listing upkeep writes, submits and refreshes one listing per store and job from the claims source, and replies to every Review. Starts at You approve the first wave.
Tactic store-quality-levers Store quality levers read each store’s ranking inputs weekly, fix install quality and performance, and apply for each badge the listing earns. Starts at You approve each one.
Tactic fixed-event-review-ask Fixed-event review ask asks every Customer once per store at the activation Event, with no sentiment filter and no reward tied to the rating. Starts at You approve the first wave.
Tactic private-offer-desk Private offer desk turns an open Deal’s Quote into a cloud marketplace private offer, and counts the marketplace as the buying path, never the source. Starts at You approve each one.
Tactic product-feed-sync Product feed sync publishes every commerce Offer variant to shopping and answer surfaces as a discovery asset, linking back to the Startup’s own checkout. Starts at You approve the first wave.
Trigger host-build-ready Host build ready: event on Version.deployed, window 30d.
Trigger org-offer-published Organization Offer published: event on Offer.published, window 30d.
Trigger listed-version Listed version: event on Version.deployed, window 2d.
Trigger activation-reached Activation reached: event on Customer.activated, window 72h.
Trigger store-review-posted Store review posted: event on Review.published, window 2d.
Trigger uninstall-spike Uninstall spike: threshold on Monitor.checked, window 7d.
Trigger store-threshold-met Store threshold met: threshold on Monitor.checked, window 30d.
Trigger vitals-breach Vitals breach: threshold on Monitor.checked, window 7d.
Trigger marketplace-buy-path Marketplace buy path: event on Quote.requested, window 3d.
Trigger catalog-change Catalog change: event on Offer.published, window 1h.
Trigger marketplace-renewal-window Marketplace renewal window: at on Renewal.opened, window 30d.
Sequence review-ask-once Review ask once: 3 steps; it ends on A Review posts on that store; The Customer opts out; The store’s prompt cap is reached; 14 days pass.
Sequence private-offer-follow-up Private offer follow-up: 2 steps; it ends on The buyer accepts the offer; The buyer declines; The Quote expires; The Deal is lost.
Benchmark subscription-app-download-to-paid Median download-to-paid conversion for subscription apps, non-AI against AI apps: 2–2.4 % (State of Subscription Apps 2026, 2026-03-19).
Benchmark subscription-app-day35-by-paywall Median day-35 conversion, freemium apps against hard-paywall apps: 2.1–10.7 % (State of Subscription Apps 2026, 2026-03-19).

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.