Free users, paid users, and the seam between them

LunarCrush · The simplified credit amounts are live in the production checkout and a copy sweep removing stale free-plan promises is on the staging branch; the credit dashboard and three-state messaging are still behind flags

A checkout that kept saying Free after a real payment, a snapshot chip that told the wrong time, and an upgrade reminder system designed from how free users actually behave.

September 23 turned into a day about the seam between free and paid: the places where a free user meets the product's limits, and the places where a paying user should stop being treated as free. It started with a support question and ended with a designed reminder system. In between, two bugs shipped to production.

A blank tab that only one phone saw

Joe posted a capture in product-main: the Stocks category on his iPhone with the header and pills painted and the body completely empty. The session data showed the tab never mounted on his device, with no error captured, while Crypto and Home rendered normally. His traffic was reaching us through Europe, which pointed at a VPN or private relay rather than the app. I searched the last seven days of product analytics for the same signature, navigations to a category followed by dead interactions on an unmounted view, and found nobody else with his pattern. The honest closure was that a request stalled mid-session on that connection, a reload fixes it, and the app cannot currently prove any of this because a blank page leaves no trace. The commitment that came out of it is front-end error capture, so the next blank screen reports what actually failed instead of requiring an investigation.

Paying and still seeing Free

Later that morning I hit a bug myself: I paid for a plan and the app kept showing me as Free. The payment side was healthy, the subscription was active, the webhook was delivered, and the analytics events arrived in the same second. The problem was on the client: after checkout inside the plans modal, the app never refreshed the profile, so the interface kept the stale plan until a full reload. The account page had already solved this exact problem with a polling routine that retries the profile with backoff for about thirteen seconds. I extracted that routine into a shared module and made the modal use it, tested the whole journey in staging with a fresh account (onboarding, payment, plan visible without reloading), and promoted it to production before eleven in the morning. Production is a curated branch that trails the development branch by almost three thousand commits, so promotion is a single cherry-pick with the full test suite and smoke checks around it.

A chip that told the wrong time

Joe also flagged a snapshot narrative that read like old news next to the live chart: the text described a surge while the price was visibly falling, and the chip said the snapshot was eight minutes old. The chip was reading the record's refresh time, not the narrative's generation time; the words on screen were hours older than the timestamp implied. The fix distinguishes the two: the snapshot now carries the moment its narrative was generated, the chip reads that, and the record refresh stays available separately. Verified in staging: the Bitcoin snapshot chip went from claiming minutes to stating the real age in hours. It is a small change that removes a lie the interface was telling without anyone having decided to lie.

Designing the reminder instead of copying one

The conversation that filled the afternoon came from product-main: how should the app remind a free user that an upgrade exists? Jon proposed the pattern he sees in TradingView, an interstitial that returns on a cadence. Joe suggested trying several mechanisms in combination. My position was to check how our free users actually behave before choosing a rule.

I collected fourteen reference captures from Mobbin across four families: periodic interstitials (Elicit, Mixpanel, Mobbin's own single-plan modal), permanent presence (Teachable's top bar, a rail card, a usage-limit bar), blurred locks over real data (charts, tables, locked sections), and exit or discount moments (before-you-go screens, a lower-price counteroffer, a countdown, a one-time offer). The board with all fourteen, each linked to its source, lives in the Paper file next to the comps.

The pattern board: fourteen captures in four families, from periodic interstitials to one-time offers, each linked to its source.

Reference board assembled on September 23 from public Mobbin captures. The recommendation at the bottom combines three of the four families.

Then the numbers, from the last seven days of production: 753 identified free users, 1,017 sessions, a median session of two minutes (p75 of 7.6), three pages per session, and 77 percent of free users who came exactly once in the week. Two consequences fell out immediately. A timer like TradingView's never fires inside a two minute session, so cadence cannot be the trigger; and with sessions this short, the reminder has to attach to the moment of value, not to elapsed time.

The rules v1 I left on the board: a one-line bar on every screen for every free session, stating that Free shows the last 24 hours and full history starts at five dollars a day; the existing 24-hour data limit made visible as real data rendered under a blur with the unlock card on top; an interstitial triggered by the second detail page of a session or the first tap on a paid control, whichever comes first, capped at one per session and three per week, never in the first sixty seconds; and a one-time 15 percent offer on the third lifetime dismissal of that interstitial, stored on the account so it never repeats. Onboarding stays untouched: the person who just saw the plans modal at signup is not reminded again in that session.

Rules v1: who sees what, the four layers, why not a timer, and how it gets measured.

The rules artboard in Paper. Every rule cites the behavior numbers it depends on.

The measurement plan is part of the proposal: three events (shown, dismissed, clicked) with surface, trigger and ordinal, chained to the existing checkout funnel, behind a feature flag with a 50 percent holdout for two weeks. Success is paid conversions per free user; the guardrail is that sessions per user and detail pages must not drop more than ten percent. I also built the comps over real screenshots of the product with a free account, at desktop and phone widths, so the discussion happens over the actual surfaces rather than abstractions.

Where the annual plans went

The same channel produced the next question: Joe noticed that annual plans had stopped arriving and asked whether something we changed explains it. I pulled every subscription and checkout session from Stripe, read-only, and crossed the dates against the pricing page's change history.

The picture was sharp. The last Individual annual came in on July 31 and the last Builder annual on June 19. August had zero new annual plans against six to eight a month earlier in the year, and September's two did not come from the pricing page: one arrived through Claude over MCP and the other is a legacy price with no checkout session at all. Upstream of that, fewer people even reach the annual checkout: from 23 opened per week between April and July down to 9 since August. And of everyone who opened one since April, 7.8 percent paid it, against 46 for daily and 56 for monthly; more of them ended up buying a shorter plan than paying the annual price.

The tempting explanation did not survive the timeline: the default billing period switched from Daily to Monthly and back during August, and neither switch lines up with the drop. Jon's reading fits the data better: people do not treat Daily, Monthly and Annual as a choice, and the few who land on the annual option meet a four-digit total. I wrote it up as a short illustrated report for the team, with the three unknowns stated plainly: nobody tracks clicks on the billing toggle, about a quarter of annual plans started as shorter plans and upgraded later, and total checkout traffic fell over the same period, so pricing and traffic cannot be separated with this data alone.

Prototyping the choice instead of arguing it

The report's options to test went into Paper the same evening, drawn over the real pricing page's tokens and copy. The first option makes the billing period look like a choice: three price cards, Daily at five dollars a day, Monthly at ninety a month, Annual at seventy-two a month marked best value, with the savings stated in dollars against monthly instead of a percent against daily. Plan details expand under a single control, the one-time 15 percent offer from the reminder system gets a variant with annual preselected, and a tracking board specifies an event per selected period, so the next investigation starts with the data this one lacked.

Then Jon looked at the report and inverted the hierarchy: make the plans the tabs, put one description with a duration selection below, and say who each plan is for. That became a second complete option in the same file: plan tabs with a who-it-is-for line and a from-price, the chosen plan's features and billing duration in one panel, and the mobile order rearranged so the buy button lands on the first screen. His follow-up observation, that everyone is a builder on every plan so the names no longer mean anything, turned the prototype's plan names into an intensity scale: Starter, Pro and Scale, with Enterprise in the pricing package's own violet after gold proved too close to Starter's amber.

Option 2 of the pricing prototypes: plans as tabs, each saying who it is for, with the billing period as a separate step below.

The plans-first option in Paper, built after Jon's feedback on the report. Names, features and colors come from the real pricing package, not invented for the mock.

One more rule came out of the session: the Paper page now follows a fixed grid, a flow board first, then one column per step with desktop above and mobile below, written down so every future screen lands in a predictable place.

Turning the reminder into a real offer

Two days later the reminder system stopped being only a generic upgrade proposal. Joe asked for a very specific monetization move: daily-plan users who had already paid five dollars should see a stronger reason to move to monthly, with a 20 percent discount and the five dollars credited into the first month. I added that as a new row in Paper, G · Day pass to monthly, below the earlier onboarding flows.

The important judgment was not to show the user a discounted monthly price first. Nico pushed the hierarchy in the other direction: make the discount the headline, then explain the math. The modal became 20% off your monthly plan, with the detail underneath: $72 a month instead of $90. The $5 you paid today counts, so you pay $67 for the rest of the month. Joe then tightened the rule: hit all daily users harder, repeat the offer because the discount matters, keep the credit explicit, and connect it to the existing billing screen.

A Paper overview of the day-pass-to-monthly flow, turning a paid daily user into a discounted monthly upgrade path.

The G row in Paper. It is not a generic paywall anymore; it is a conversion path for someone who already paid once and has a credit to apply.

That one moved faster than the larger reminder system. A staging deploy for the DAYPASS20 account billing path landed on September 25, and the automated staging checks passed. I started recreating the exact staging screen back into Paper, then stopped and deleted the partial artboard once it was clear the deploy itself was already verified and the duplicate design artifact would add noise. The implementation evidence is staging plus the passing checks, not the abandoned artboard.

The data-product funnel underneath the same problem

The other thread on September 24 and 25 widened the same question from self-serve pricing to enterprise value. Joe challenged the onboarding readout: 37 people paid after reaching plans, but MRR is the number that matters, and retention matters more than raw signups. I pulled the answer back to behavior: on the $90 monthly plan the product loses about one in five accounts every month, and 87 percent of the $90 users who stay use the API or MCP. The next useful question is not just whether the new onboarding converts, but what stayers did in their first two weeks.

That led to a separate Paper track for the enterprise customer lifecycle: discovery, NDA and diligence, a trial or backtest, contract, integration, monitoring, and organization management. I researched how data vendors sell to banks, funds and brands, then split the work into screens: connectors, datasets, delivery, members, plans, and the return path back into Claude. This is adjacent to the free-to-paid seam, not the same article's core deliverable. I am recording it here because it changed the monetization framing: the paid product is not only a higher limit, it is a workflow where teams connect data, share access, and keep the data flowing outside the app.

Closing the pricing comments with the real product model

On September 28 the pricing work came back as a concrete cleanup pass, not another open exploration. Nico pointed me back to the Paper file and asked me to resolve the comments on the pricing page. I treated the repo as source of truth before changing the design: the pricing package, not memory, decides plan names, included calls, limits and feature language.

The first correction was hierarchy. Jon did not want the tabs to repeat price, so the tabs became plan choices with a short audience line, while billing period moved into the selected plan panel. The second correction was content. The Medium plan needed to say what it actually includes, with calls per day and the right included order, not a generic list. The third correction was comparison: mobile still needed the compare-plan content to be useful without becoming a wall. I pushed those fixes across pricing and the onboarding pricing screen so the two surfaces would not drift.

The corrected pricing direction keeps plans as the primary choice, then makes billing period a second decision inside the selected plan.

The September 28 pricing pass. The visible work is less about making a nicer pricing page and more about making the product model legible enough to test.

That same pass also made a small but important naming decision. Enterprise uses the product's violet, not the amber used for Starter, because the pricing system needs to separate the self-serve ladder from the sales-led plan at a glance. Sophie and Beacon moved into the Enterprise language because that plan is where the product starts looking like a managed workflow, not just more usage.

API usage emails and the limit moment

The reminder system also grew a developer branch. Earlier work had focused on free users in the app, but API users have a different moment of truth: they either have not made calls yet, they are about to hit a limit, or they are already seeing weekly usage. I added email and in-app surfaces for those states: a no-calls-yet email for a free API user, a limit-reached email, a small in-app card on the developer overview, and a weekly usage email for paid subscribers.

The rule is the same as the upgrade reminder, but the surface changes. A consumer can be nudged inside a topic page. A developer needs the message at the point where the integration work either starts or stalls. That is why the copy avoids generic marketing language and instead names the operational state: no calls yet, limit reached, weekly usage, plan fit.

The enterprise funnel became a real sequence

The biggest addition was the enterprise track. The previous version of this article recorded the enterprise lifecycle as a framing exercise: discovery, diligence, trial, contract, integration and monitoring. On September 28 that became a set of screens in Paper.

The first version was a sales page with a pilot request form. After reading the meeting transcript, I changed the call to action from a generic pilot into Talk to us, because Joe and Jon were talking about a conversation-led enterprise motion, not a self-serve checkout. The page frames the offer around data products, Claude, API access and Beacon, then the form asks for enough context to route the conversation without pretending that a contract starts there.

The enterprise page frames the paid product as a data workflow, with Talk to us as the action instead of a checkout button.

The enterprise page in Paper after the CTA shift. It separates the sales-led workflow from self-serve pricing without inventing a new product.

Then I added a gated backtest download flow. This is not a paywall in the usual sense. It is a trust gate for a high-value artifact: enter a work email, receive a code, unlock the download, or wait while the request is reviewed. The flow gives the enterprise page something concrete to offer while still respecting the reality that some data products need qualification before release.

The gated backtest download flow gives the enterprise funnel a specific artifact, with work email, code entry, ready and in-review states.

The download states are designed as product evidence, not a generic lead magnet. The form has to earn trust before it can ask for company information.

A topic page with no posts

One smaller product edge came from Joe's New York Times example: a phrase topic had been created, but the page still looked broken because it had no posts yet. I traced the path through production and confirmed the odd state: the route can show a topic shell while the social content is still collecting. The design response was not to fake activity. I added variants for the phrase topic state, first explaining that the topic is still collecting posts, then a more search-like version that admits there is no content yet while preserving the next useful action.

The phrase-topic empty state keeps the topic page useful without pretending that posts already exist.

The empty state work is part of the same pattern as the pricing work: say what the system actually knows, then give the next action.

The day-pass offer reached production

On September 28 the day-pass-to-monthly offer moved from staging into production. The promotion was intentionally narrow: only the DAYPASS20 path went live, not the broader pricing and enterprise work still sitting in Paper. I verified the production functions directly: the offer endpoints require a logged-in user, the reminder endpoint requires its password, the hourly process can find the function, and the old generic email endpoint is gone. Resend was removed from the production environment as part of the cleanup, so the offer path no longer depends on that mail key.

This changes the status of the work without changing the lesson of the article. The discount modal is not a generic paywall idea anymore. It is now a production conversion path for a user who already bought a day pass and can be moved to a monthly plan with the credit explained clearly.

Pricing stopped being only a design artifact

On September 30 the pricing thread crossed a line from Paper to the live product. Jon left another round of comments, and the useful constraint was that the page could not become a pricing essay. The headline changed to Real-time social intelligence for research, decisions, and AI. Coverage, historical depth and AI access moved directly under the headline, so the first screen tells a buyer what kind of system they are entering before it asks them to choose Light, Medium, Heavy or Enterprise.

I kept the plan model from the Paper work: plans as the primary tabs, billing period as the second decision, with monthly as the default instead of annual. The No thanks exit in the modal moved to the bottom edge, the plan names and prices matched the current package, and the comparison, Sophie and FAQ handlers were wired on the page. The production verification was not just visual. I checked lunarcrush.com/pricing on desktop and mobile, and the PostHog stream received the thirteen expected pricing events from the test visit: page view, tab changes, billing changes, checkout starts, compare interactions, Sophie and FAQ actions.

That turned the pricing pass into a shipped surface, not just a proposal. It also kept the larger lesson intact: the product should not ask for money before it has explained the work it can do.

Preserving intent through login

The next failure was smaller and more dangerous because it lived between surfaces. A signed-out user could choose Light daily on pricing, click Get Light, leave for Google login, and land on Home with the selected plan lost. For a new account, the path fell back into the onboarding plans modal. For an existing account, payment could still happen later from Account, but the original decision had disappeared.

I rebuilt the path with before and after evidence in Paper, then fixed the handoff so the login step saves the pricing return URL before leaving for Google. After the fix, the same real path returns to /pricing?subscribe with the Light daily checkout open. I verified that journey in production up to the Google boundary and back to the checkout state. This is the same pattern as the checkout refresh earlier in the week: payment design is not only the modal. It is the continuity of intent across authentication, plan state and return routes.

The authorize screen became an onboarding problem

The same monetization work also touched /authorize, where people arrive from Claude or ChatGPT. Jon's feedback was that the right panel should say more about what people can do, not only list platform features. I translated that into three directions in Paper. A · Clear keeps the current product loop and shows real prompts with real answers. B · Human tests a more cinematic story about social intelligence starting small. C · Mixed combines people with a real LunarCrush answer frame composited into the scene.

None of those directions shipped in this run. The value is that the login screen is no longer treated as decoration. It is part of the free-to-paid seam because it explains why connecting LunarCrush to an LLM is worth finishing, especially for the users who arrive from outside the app.

The analytics caught up with the offer

On October 1 the same seam moved from pricing copy into measurement. Jon's question was simple: twelve new signups in a day is unusual, so where do we see whether the changes are converting? The admin Analytics view already had account data, but it did not explain the revenue path well enough. I separated the work into two views. Revenue now shows where a payment started, which screen and button opened checkout, and how a day-pass buyer moved into a monthly plan. Onboarding now separates the normal app flow from Claude and ChatGPT authorization, because an LLM connector has a different path: connect, maybe see plans, maybe pay, then return to the assistant.

One detail proved why this matters. A real row looked contradictory: current plan Monthly, charge $5. The raw facts were both true. The user first bought a Light day pass, then upgraded to Light monthly with the 20 percent day-pass-to-monthly offer. The table now says Light · Day pass to Monthly and names the coupon as the offer, instead of flattening two decisions into one confusing row. The tracking pipeline also moved from a manual sync into a Cloudflare worker that runs every fifteen minutes, so the revenue view is not stale when the team is trying to read the day.

The October 1 verification closed the login concern too. I ran the full production pricing path with email login and the Google path up to the real handoff, then simulated the same callback shape Google uses. Both returned to /pricing?subscribe=Individual&cycle=daily and opened the Light daily Stripe checkout. The remaining proof is observational, not mechanical: the next real signed-out buyer from pricing should show up in PostHog as a checkout from pricing instead of a visit that fell back to Home.

A parallel thread from Dan changed the free-user limits underneath the same product question. The API now applies more of the unsubscribed limits itself, including current metrics, 24-hour or 30-day historical windows, three top creators and four top posts in several paths. I compared the direct API and our current proxy before proposing a simplification. The direct API and the proxy still differ in ways that affect the interface: hourly Bitcoin history, Elon Musk posts, and creator lists do not all line up yet. So the right next step is not to delete the proxy blindly. It is to remove duplicate limiting only after each endpoint proves it can support the same product promises.

The connector screen became a conversion surface

On October 2 the /authorize work became less theoretical. The screen that people see after coming from Claude or ChatGPT had been listing allowances and prompt counts. That was backwards: a user arriving from an LLM has already shown intent, so the screen should help them finish the connection and understand the benefit of the plan in the language of the job they are about to do.

I rewrote the plan headlines around use instead of quota: Free Trial is for trying real-time social data in an LLM, Light is for researching markets and narratives from the LLM, Medium is for building dashboards and agents on social data, and Heavy is for running social media sentiment in production. The prompt counts disappeared from the flow. So did the generic return text: a user who arrives from ChatGPT now sees Back to ChatGPT, not a platform-neutral escape hatch. The login video also moved to the same language, ending on The Social Media Sentiment Layer without the glow behind the logo.

The second decision was an A/B change to the Free path. The first read of the funnel showed that people who chose the free trial were being asked to reconsider immediately: after Start free trial, the primary button still pushed upgrade while the route back to the LLM became secondary. The early numbers were small, but the drop was enough to expose the design problem. I changed the default billing period on /authorize to Monthly, and after a free-trial choice made the primary action the return to Claude or ChatGPT. Upgrade stays available, but it stops interrupting the intent the user just expressed.

This is still an experiment, not a conclusion. The next honest read comes after a few days of traffic. The product decision is already clear, though: the connector screen is not a marketing page. It is part of the checkout seam, because it decides whether a user who arrived with intent leaves with a working connection, a paid plan, or confusion.

October 4: the pricing page got quieter

The October 4 production pass was not another strategy change. It was a tightening pass after Jon approved the direction: the phone headline now breaks into two readable lines, Coverage and History sit as one compact promise, network icons stack cleanly, and the comparison section says Compare Plans without an extra explanation line. I verified the live pricing page on desktop and phone after the production deploy.

The important part is restraint. Earlier pricing work had to explain the product model. This pass removed the parts that were still trying too hard, while keeping the same hierarchy: explain the intelligence layer first, then let the plan model do its job.

October 5: the Free promise reached production

The October 5 work closed a risk that had been sitting under the monetization story since Dan moved unsubscribed limits into the API. Staging briefly showed the wrong product promise: Free users could see more than the last 24 hours in some chart paths because the app read the new API shape too directly. I fixed that locally first: Free stays a one day product in the interface, while longer windows remain paid. That correction exposed the real boundary. The API itself still returns more history in some places, so the product cannot remove every proxy or guardrail until each endpoint matches the promise exactly.

Later that day the production path shipped. The site now uses the server data path for Free users, and I verified it on lunarcrush.com: Bitcoin and Elon Musk returned 24 hourly rows without the old grant header, and a creator page that had collapsed to four posts for guests returned 35 posts after the fix. Similar Creators appeared for CryptoTony both signed out and signed in, and the NPC coin page showed the real coin data instead of a nearly empty catalog topic.

This is not only an engineering cleanup. It is the free-to-paid contract made concrete: Free gets live 24-hour social data, paid plans get history and production use cases, and the interface should not accidentally give a different promise because two data paths disagree. The remaining dependency is clear and belongs upstream: the public social fallback cannot be retired until the API can provide the last 24 hours of creator posts for Free users by itself.

October 6: plan names had to survive email and support

The next day exposed the same monetization seam in two smaller places: a marketing email and a support conversation. Jon was preparing a Beacon email about the plan rename. The first draft said Starter, Medium and Heavy, but the live pricing page and the app used Light, Medium and Heavy. I treated the mismatch as a product consistency problem, not just a graphic request. The hero became a reusable compositor: old plan names struck through, new names in the current pricing colors, and the same plan icons the app uses, Feather for Light, Lightning for Medium and Barbell for Heavy.

The approved email hero uses the current plan names, app icons and pricing colors instead of inventing a campaign-only visual system.

The approved Light version for Beacon draft 20. It keeps the email on the product system: current names, current colors, no logo, no decorative campaign layer.

After Nico chose Light, the Beacon PR was integrated and Jon got the handoff: change draft 20 to a one-off email, keep the content, and replace Starter with Light in the body. When Jon asked how to copy a campaign, I found the existing template workflow and started a one-click duplicate action for drafts. The useful part is not the button itself. It is the rule underneath: a pricing rename cannot live in one surface while checkout, Beacon and the app say something else.

The support thread later that day made the offer logic tangible. A Free user accepted the 15 percent forever offer, reached checkout, left without paying, and then could not get the offer back. The internal coupon name, 15FOREVERAPP, looked like a code but was not one; the real typed code was 15GO. I first clarified the situation in product-main and, after approval, answered the Beacon ticket with the code. Then I changed the site logic so an accepted but unpaid offer can be recovered from Account, Change plan, and so the 404 game shows its code to signed-in users who are still Free. By the cutoff, the code had tests and had been pushed to webapp-dev, but staging verification was still waiting behind newer deploys.

That is why I am keeping it in this same article. It is not a separate campaign story. It is the same seam: if the product asks someone to move from Free to paid, every name, coupon, return path and support answer has to preserve the decision instead of dropping it between systems.

October 7: the product update email got real images

The plan-name email was followed the next day by the October product update itself, Beacon draft 23. Jon asked for its in-body images; the draft had the same placeholder in all eight slots. I reused the compositor system from the August release email, same field color, dot visualization and framed screenshot card, rendered at twice the slot size so nothing arrives soft. The eight captures are the production site itself: the free 24-hour category view and pricing captured logged out, the feature views captured on a paid test account with the personal sidebar cropped out, and each screenshot pre-cropped to the card's aspect before compositing so no text is cut mid-word. The pipeline is a script away from re-rendering, which matters because an email like this changes twice before it sends.

October: the seam grew a pricing model

Through late October the seam stopped being a collection of fixes and became a pricing model. A working session with Jon and Dan settled the shape: pay-as-you-go, credits only, no base charge. Dan said it plainly, "it sounds like we just want to do pay-as-you-go". Credits cover the API, MCP and the CLI; the Discover web app and Recipes stay with subscriptions. I had checked the code first: none of this existed, not in branches and not in the CLI, so the first build was real work, not wiring. Within days staging had the pricing page with Pay-as-you-go and Subscription as two tabs, credit buckets with volume bonuses, auto-recharge, a Due today line, and a new account dashboard for credit users behind a feature flag, with a balance function that reads paid purchases from Stripe because the profile does not carry the customer id.

The design problem underneath was states, not screens. A site without a subscription is really three different users: signed out, signed in free, and someone who already bought credits. The interface knew only the first two. I built the full state matrix against the actual code, surface by surface, and wrote every message under one rule with three questions in order: what you have, what you cannot do here and why, and what to do now. Nobody who already paid ever reads the word Upgrade.

Two decisions tightened the model. Jon collapsed the entry: everyone who signs up anywhere, Claude, ChatGPT or lunarcrush.com, gets 1,000 free credits, and subscribing adds another 1,000, so every account starts inside the same economy. Dan kept the billing honest: a prepaid credit system has no monthly concepts, discounts live on the size of the purchase, not on a calendar. Each decision landed in Paper as a dated block, and Jon's ten comments on the state boards came back resolved the same way: Recipes out of pay-as-you-go, favorites only for subscribers who have favorites, and a Your plan row so the paid states stop reading as all credits.

The rest of the month was the unglamorous half of the work: feedback rounds with Jon over staging about alignment, uppercase buttons, the manage-plan card, and an add-credits flow that now swaps the right-hand panel instead of opening yet another surface; onboarding and payment emails built in Beacon and merged; and the repeated discipline of updating Paper before staging, so the review happens on the design surface instead of on screenshots.

November 5: production says pay-as-you-go

After Jon's green light, the model crossed to production. I verified the public pricing page on November 6: lunarcrush.com/pricing now opens with "Pay-as-you-go is $1 per 1,000 requests across the API, MCP, and CLI; subscriptions include the LunarCrush Discover app." What I verified is the copy and the page, not a production credit purchase; that proof belongs to the first real buyer in the analytics.

The authorize thread from October also closed its loop. The login panel's video had been selling the LLM connection; Joe's note was that the first click after GET STARTED should get people more excited, and the subscription needed its own story. The November 5 cut reuses the proven footage system, six shots of three seconds in an eighteen-second muted loop, and replaces the screens with real ones: the actual Discover crypto table tracked into a monitor, real 24-hour engagement numbers, the real all-time Bitcoin chart, ending on the subscription offer instead of the API. Same system, different buyer.

November: every account state got a screen and an email

When the model crossed to production, the remaining work was coverage: making sure every state an account can be in has a screen that tells the truth, and an email for the moments when the product cannot reach the person at all. Through late October and the first week of November the working file grew into that full specification, and this week the bridge captured the boards live, so the pass is finally reviewable as actual design surfaces instead of session notes.

The screens half maps the whole seam at two widths, because the earlier passes kept finding phone-only failures. The public pricing page settles into two tiles with one entry point: pay-as-you-go at the public $1 per 1,000 requests rate, with a terminal example that costs exactly one credit, and subscriptions from $5 a day with the Discover app. Behind it sit the states the October matrix only described in prose: sign-up steps on a fixed card so the inputs and the button never move while you type, the first pricing step after sign-up in both chosen states, the Stripe checkout embedded as a layer whose close returns you to the plans instead of stranding you, account billing drawn separately for a credit user and for a subscriber, and Discover locks that send a signed-out visitor to sign-up but a signed-in one straight to billing. The LLM onboarding thread closed the same way: version boards now document the arc from the original flow, where logging in with Google lost the plan you had chosen, through the fix that saves intent before the redirect, to the current connector flow, laid out as captioned before and after rows anyone can audit.

The public pricing page as two tiles with one entry point, captured from the working design board: pay-as-you-go priced per request on the left, subscription with the Discover app on the right.

The emails half is the genuinely new layer. A prepaid system has no cancellation moment: nobody calls to leave, they just run out. So the proposal treats email as the interface for everyone who grabbed a key and never came back to the site. Each account state gets one message built on the same three questions as the screens: what you have, what just happened and why, and the one obvious thing to do now. A welcome that works as a receipt for the starting credits and repeats the key instructions, because many builders never open the dashboard again. A heads-up when the balance covers about two days at that user's own recent pace, not a generic threshold. An out-of-credits note an hour after the first refused call, showing the real error the integration saw. A failed-payment notice, and a suggestion to switch to a subscription only in the months when a subscription would actually have cost less. Usage emails for API users follow the same honesty rule: the weekly note for paid accounts reports where the calls went and sells nothing unless the numbers justify it.

The welcome email for a new account, designed as a receipt for the starting credits with the key instructions up front. A proposal in design, not a shipped campaign.

The boundary is the same as the rest of this chronicle. The pricing copy is public and live. The screens and the email system are design coverage: specified, reviewed on the boards, and waiting on build, including an engineering dependency the boards state plainly, a per-account usage feed into the email tooling, before the usage emails can tell the truth they are designed to tell.

November 10: trust work on the paying side

With the model public, the bugs that matter changed sides: they stopped being free users hitting walls and became paying users doubting the product. November 10 was a day of that second kind.

The first case arrived as a support question that smelled like a double charge: a customer with two identical credit purchases 25 seconds apart. I traced both payments end to end before touching any code. The conclusion was that nothing double-charged; the customer completed two one-click checkouts, both were credited, and the screen after paying gave no strong confirmation that the first one had landed. So the fix is not a refund pipeline, it is a louder confirmation: the purchase window now overstates its result on purpose, showing what you just bought and what your balance became, so repeating the purchase takes intent instead of doubt. The team decision that came with it also simplified the surface: the add-credits flow only sells credits, it never changes your plan, and each account type sees only the options that belong to its own model.

The second case was quieter but touched every paying surface: the account pages (manage, change plan, payment method, billing history, cancel, delete) rendered correctly while the browser tab called them "Page Not Found", because the server only wrote titles for the exact account address and not its subpages. I reproduced it on production, then ran every route through a headless browser comparing the tab title against what the page actually renders, fixed the set it found, and shipped. A paying user reading "Page Not Found" over their own billing history is exactly the kind of small lie this chronicle exists to catch.

Both fixes are live in production. The support assistant's verification-code flow also got repaired and verified end to end the same day, with a test purchase conversation confirming the code now arrives.

What shipped and what waits

The checkout refresh, the snapshot chip, the day-pass-to-monthly offer, the revised pricing page, the quieter October 4 pricing refinements, the Google-login return fix, the connector authorize copy, the production Free 24-hour server path and the Beacon plan-rename assets are in production or ready for the campaign owner. Revenue attribution and the LLM authorization analytics are active internal tooling, and the Free-path A/B test on /authorize is live but not mature. The recoverable 15 percent offer, the draft duplicate action, the broader reminder system, API usage emails, the phrase-topic empty state, the enterprise funnel, the INSIDER15 onboarding discount and the larger authorize hero directions are still staged or designed work, not fully shipped customer surfaces. The distinction matters: the first two were the product failing to tell the truth, and the rest is a decision about how the product asks for money, which deserves its holdout and its tracking before anyone trusts it. And the pricing model itself has now crossed over: pay-as-you-go is public copy on the production pricing page and the simplified credit amounts are live in the production checkout, while the credit dashboard and the three-state messaging keep maturing behind flags.

November 11: the price list got simpler and the copy stopped promising free

Two kinds of pricing truth got work the next day.

The first was the amounts themselves. The credit packages had been $5, $20, $50 and $100, with $100 sitting there as a jump nobody was forced to make. The list is now $5, $10, $20, $50 and Other, with $5 still preselected and Other covering any larger amount. The change lives in one shared price definition, so onboarding, Add credits, Change plan and the dashboard credits card all follow it. It went to staging, got reviewed there, and was then promoted and verified on the production site the same day: the add-credits screen on lunarcrush.com now shows the new row.

The second was older copy still promising a free plan. The public FAQ still asked whether there is a free plan or a free trial, with the old answer, and the About and brand pages carried similar leftovers. Each answer got rewritten around the real model, using only figures already public in the product: $1 per 1,000 requests, 1,000 starting credits, credits that do not expire. Those changes are committed to the product's staging branch with one honest caveat: the staging build currently renders the proposed new brand on every landing page, so copy changes to the current site can only be confirmed once they reach production. They are written and pushed, waiting where they can be seen.

Two smaller fixes rode along, both verified on staging with desktop and mobile screenshots. Enterprise accounts stopped being offered the subscription grid: Change plan now states the plan and offers contact instead, and Add credits says what it actually does (credits add to the Enterprise plan) in one line that fits on a phone. And the API reference dropped its infinite scroll: one endpoint at a time with previous and next, so the page stops growing under the reader.

This entry is part of the LunarCrush rebuild.

Rebuilding LunarCrush

Nicolás Bañados