How another team uses MorePaying

Point the widget at MorePaying. See the first weekly judgment on the playground before you pay.

Never send Stripe secret keys to MorePaying. Sync totals and customer ids only.

  1. Step 1

    Never send Stripe secrets

    MorePaying is read-only on money. Keep sk_live / webhook secrets on your server. We store totals and customer ids only.

  2. Step 2

    Identify at the paywall

    Call identify with user, channel/UTM, plan, signed-up-at, generations, first success, remaining credits, pricing dwell, and Stripe amount. Customers only pick a reason.

  3. Step 3

    Ask in the product, not by email

    Email surveys die. After identify, track("pricing_exit") or track("paid") opens one in-app question. That is the box. Do not add an ESP.

  4. Step 4

    Count the funnel

    track("pricing_view") when the pricing page opens. track("pricing_exit") or track("paid") asks the one question. That is how 327 / 84 / 31 is built.

  5. Step 5

    Sync paying from your Stripe account

    On your server, list subscriptions or handle webhooks. POST /api/stripe/sync with currentAmountCents, currentCustomers, and { stripeCustomerId, amountCents, status, userId }. The scoreboard source becomes stripe.

  6. Step 6

    Ship, then watch more paid move

    Agent pick → ready (git trailer MorePaying-Ready: <id>) → release --through <deployed SHA>. Release snapshots current paying and attributes blocked revenue so more paid this period moves. Later Stripe syncs fill 7 / 14 / 30 day windows.

  7. Step 7

    Open the weekly page

    Every Monday open /report: reasons, channels, three merged failure patterns, the experiment to run, blocked revenue. CSV is there. Slack comes after a real customer. Do not email a survey.

How it works

  1. 1

    Capture

    After identify, track(pricing_exit) or track(paid) opens one in-app question. Do not email a survey.

  2. 2

    Check

    Choices roll into blocked revenue. The sentence is a hypothesis until usage agrees.

  3. 3

    Agent picks up

    MCP, CLI, or /morepaying pick. After ship, notify that person.

  4. 4

    Ship

    Public board: received → in progress → pending release → shipped. Score is more paid this period.

Why it matters

  • One question

    Fixed choices at pay, don't-pay, first result, checkout, cancel. No founder fields on the customer.

  • Why they pay too

    Paid success is a first-class moment, not an afterthought.

  • Blocked revenue

    Reasons roll up to people × estimated dollars. Do this first, don't cut price.

  • Trust check

    The sentence is a hypothesis. Leftover credits and free-enough exports get flagged.

  • MCP + CLI + Skills

    list, pick, ready, release, notify, paying.

  • More paid scoreboard

    Baseline vs tracked paying amount. Seats are the plan. Lift is the score.

  • Channel × money

    Which source paid, which only blocked revenue. Ask in the product, not by email.

Attach to a live paywall

Start with a site that already has a real paywall. The widget is cross-origin. Do not put sk_live or emails in the browser.

MKSaaS credit sites (seedvr2 / plain / aiupscale / happyhorse)

<!-- layout: once -->
<script src="https://morepaying.charlie0simmon.workers.dev/widget.js"></script>
<script>
  MorePaying.init({
    projectKey: "mp_proj_YOUR_KEY",
    apiBase: "https://morepaying.charlie0simmon.workers.dev"
  })
</script>

// after session + credits load
MorePaying.identify({
  userId: session.user.id,          // hash if you do not want raw ids on the board
  plan: session.user.plan,
  creditsRemaining,
  creditsLimit,
  firstSuccess,
  generations,
  utmSource: url.searchParams.get("utm_source"),
  channel: session.user.channel
})

// PricingPopup open
MorePaying.track("pricing_view")

// PricingPopup closes without a purchase
// seedvr2: replace PricingDismissFeedback with this one question
// plain / aiupscale / happyhorse: hook onOpenChange(false)
MorePaying.track("pricing_exit")

// first paid-looking result
MorePaying.track("first_result")

// webhook / server only — totals, never sk_live
POST https://morepaying.charlie0simmon.workers.dev/api/stripe/sync
X-Project-Key: mp_proj_YOUR_KEY
{ "currentAmountCents": 315000, "currentCustomers": 24, "customers": [] }

ShipAny credit sites (hunyuan / longcat / lyria / trellis)

Empty credits currently toast and the user leaves. Attach by opening pricing and asking the question.

<!-- layout: once -->
<script src="https://morepaying.charlie0simmon.workers.dev/widget.js"></script>
<script>
  MorePaying.init({
    projectKey: "mp_proj_YOUR_KEY",
    apiBase: "https://morepaying.charlie0simmon.workers.dev"
  })
</script>

MorePaying.identify({
  userId: user.id,
  plan: user.plan || "free",
  creditsRemaining: remainingCredits,
  creditsLimit
})

// today: toast.error(insufficient_credits) and the user leaves
// change: open /pricing AND ask
if (!hasEnoughCredits) {
  MorePaying.track("pricing_view")
  MorePaying.track("pricing_exit")
  router.push("/pricing")
  return
}

Install

Skills teach the workflow. MCP and CLI read and update signals. Release stays in the CLI so a deployed SHA can be verified.

$ npx -y --package github:CharlieLZ/morepaying -- morepaying
$ npx -y --package github:CharlieLZ/morepaying -- morepaying-mcp
# copy packages/skills/morepaying/SKILL.md into your agent skills folder
MorePaying.init({
  projectKey: "mp_proj_YOUR_KEY",
  apiBase: "https://morepaying.com",
  userTokenFn: async () => {
    const res = await fetch("/api/identity-token", {
      method: "POST",
      headers: { "Content-Type": "application/json", "X-Project-Key": "mp_proj_YOUR_KEY" },
      body: JSON.stringify({ userId: currentUser.id })
    })
    return (await res.json()).token
  }
})

MorePaying.identify({
  userId: currentUser.id,
  plan: currentUser.plan,
  usage: currentUser.usageLabel,
  signedUpAt: currentUser.createdAt,
  generations: currentUser.generations,
  firstSuccess: currentUser.firstSuccess,
  creditsRemaining: currentUser.creditsRemaining,
  creditsLimit: currentUser.creditsLimit,
  utmSource: url.searchParams.get("utm_source"),
  channel: currentUser.channel,
  pricingDwellMs: dwellMs,
  stripeCustomerId: currentUser.stripeCustomerId,
  stripeAmountCents: currentUser.amountCents,
  stripeStatus: currentUser.stripeStatus
})

MorePaying.track("pricing_view")
// later
MorePaying.track("pricing_exit")

// on your server, never in the browser
POST /api/stripe/sync
X-Project-Key: mp_proj_YOUR_KEY
{
  "currentAmountCents": 315000,
  "currentCustomers": 24,
  "customers": [
    { "stripeCustomerId": "cus_123", "amountCents": 2000, "status": "active", "userId": "usr_123" }
  ]
}

Open the weekly judgment on a shareable page. No extra host required to start.

See the first judgment free

Stop guessing why they didn't pay.

One question when they don't upgrade. Watch the card appear on the board.

Free now. No card on Free. Paid plans check out through pay.yito.ai.