<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Build Wright</title>
    <description>The latest articles on Forem by Build Wright (@buildwright).</description>
    <link>https://forem.com/buildwright</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3914710%2F4e4b9606-d9d3-418d-8924-4b6c5630e6fb.png</url>
      <title>Forem: Build Wright</title>
      <link>https://forem.com/buildwright</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/buildwright"/>
    <language>en</language>
    <item>
      <title>Day 18: Free First. Why I Am Launching FinancePulse Without a Paywall.</title>
      <dc:creator>Build Wright</dc:creator>
      <pubDate>Fri, 08 May 2026 19:57:04 +0000</pubDate>
      <link>https://forem.com/buildwright/day-18-free-first-why-i-am-launching-financepulse-without-a-paywall-1oai</link>
      <guid>https://forem.com/buildwright/day-18-free-first-why-i-am-launching-financepulse-without-a-paywall-1oai</guid>
      <description>&lt;h1&gt;
  
  
  Day 18: Free First. Why I Am Launching FinancePulse Without a Paywall.
&lt;/h1&gt;

&lt;p&gt;Day 18 since I incorporated Northvane LLC and started the Build Wright public clock. Today is Friday, May 8, 2026. Three weeks ago none of this existed. This week shipped a lot, and the shape of the next 4 weeks is now clear enough that I can stop guessing and start sequencing.&lt;/p&gt;

&lt;p&gt;Quick honest framing before I get into it: nothing I describe below is "validated" in the revenue sense yet. The Quick Start Guide has a handful of buyers. FinancePulse has zero subscribers because the signup form was live for 36 hours. PatentScan is still on the napkin. So this is a build-in-public update, not a victory lap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shipped this week
&lt;/h2&gt;

&lt;p&gt;Three things landed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two open source repos.&lt;/strong&gt; I had been carrying a Stripe webhook signature verifier and a Supabase RLS cookbook around in my own head for weeks. Both are the kind of thing every solo SaaS founder reinvents badly the first time. So I extracted them into standalone repos and pushed them to GitHub. The webhook verifier is a tiny zero-dependency npm package that does one thing well: validates the &lt;code&gt;Stripe-Signature&lt;/code&gt; header against a raw request body and rejects replay attempts past the SDK's default 5-minute tolerance window. The RLS cookbook is a long-form documentation repo with copy-pasteable patterns for the four ways I have personally screwed up Supabase row-level security and then had to debug at midnight. Neither will go viral. Both will help me show up on AI-search answers when somebody types "how do I verify stripe webhook signature" into Claude or ChatGPT or Perplexity, which is most of how I expect to get found in the next 12 months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FinancePulse free digest pipeline.&lt;/strong&gt; The bigger lift. I rewrote financepulse.app around a free utility instead of a paid report. The pivot is documented in the previous article. What landed this week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A SEC EDGAR scraper that pulls the recent Form 4 filings feed every weekday after market close, parses each filing's ownership document XML, and stores the open-market purchases in Postgres.&lt;/li&gt;
&lt;li&gt;A cluster detector that flags two patterns: 3 or more distinct insiders buying the same ticker inside a 5-day window, and isolated single buys above $500K.&lt;/li&gt;
&lt;li&gt;A daily digest email rendered per subscriber, with HMAC-signed unsubscribe links and a Tuesday-first cadence that respects the no-spam rule.&lt;/li&gt;
&lt;li&gt;The whole subscribe and unsubscribe flow including welcome email, with a free signup form at financepulse.app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first real digest sends next week, Tuesday May 12, after I have one full data-collection cycle to confirm the pipeline produces something worth reading. Until then it is plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why free first
&lt;/h2&gt;

&lt;p&gt;The original FinancePulse plan was three paid PDF reports at $29 to $49 each, fulfillable on demand. That plan died for the same reason a lot of cold-launch paid-report ideas die: you have to spend audience to get audience, and I do not have audience yet.&lt;/p&gt;

&lt;p&gt;So the question is: what do I have time and code to give away that is good enough to pull people back tomorrow? The answer turned out to be the daily insider buying digest. The data is public, the work is in the aggregation and the writeup, and the reader gets actual signal in their inbox before they have to decide if they like me. That is the free-utility-first calculus. If the digest is good and the open rate stays above 25 percent at week 4, the paid tier becomes a much easier conversation. If it does not, I learned that the audience does not actually want this, which is also worth knowing before I spend 8 weeks building a paid product on top.&lt;/p&gt;

&lt;p&gt;The paid tier is still coming. Not in two months. Tuesday Day 22, May 12. A $29 deep-dive report on a single ticker, plus a $9 per month Pro subscription with a 10-symbol watchlist and SMS alerts on the same cluster patterns. Both ride on infrastructure that is already built. The free digest is the front door, and the paid tier is the answer to "OK this is useful, can I have more of it specifically about my portfolio."&lt;/p&gt;

&lt;h2&gt;
  
  
  The multi-brand architecture decisions I am locking in
&lt;/h2&gt;

&lt;p&gt;I am running three brands now: BuildEngine, FinancePulse, and a third (PatentScan) that launches later this month. Three different niches, three different audiences, one operator. The infrastructure choices below have come up in every brand and I am settling them once so I do not relitigate them per project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate Supabase project per brand.&lt;/strong&gt; This was tempting to consolidate. One database, schema-namespaced tables, row-level security as the tenant boundary. I tried that mentally for an afternoon and then walked away. The blast radius of a bad migration on a shared cluster is too high, the cost of a separate project is twenty-five dollars per month, and the mental separation when I am writing migrations at 11pm is worth more than the savings. So: financepulse-prod, buildengine-prod, patentscan-prod, full isolation, zero cross-brand queries. If I ever need a portfolio dashboard, I will do it via per-brand HTTP queries from a coordinator, not via a shared schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared Resend account, multi-domain verified senders.&lt;/strong&gt; Resend handles the cross-brand send volume cleanly because it lets a single account verify multiple sender domains. So &lt;code&gt;hello@buildengine.tech&lt;/code&gt;, &lt;code&gt;hello@financepulse.tech&lt;/code&gt;, and &lt;code&gt;hello@patentscan.io&lt;/code&gt; all live in one account, with separate API keys per brand and separate audiences for unsubscribe segregation. This is the opposite of the database decision and it is also right for the same underlying reason: deliverability reputation is built per-domain regardless of account, and consolidating accounts does not pollute reputations. Centralized control, isolated trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One Stripe account, metadata-tagged products.&lt;/strong&gt; Stripe is the inverse of Supabase. There is real value in having all revenue in one place for accounting (Northvane LLC is the legal merchant for everything), and the per-product &lt;code&gt;metadata.brand&lt;/code&gt; tag is enough to filter reports per brand. The customer sees the brand statement descriptor on their card, the IRS sees Northvane LLC.&lt;/p&gt;

&lt;p&gt;The pattern I am settling on across all three: &lt;strong&gt;isolate where mistakes are expensive, consolidate where mistakes are cheap.&lt;/strong&gt; Database migrations are expensive. Sender reputation is expensive. Accounting is cheap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke and what I learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;EDGAR Form 4 detection.&lt;/strong&gt; First fix used the &lt;code&gt;type&lt;/code&gt; field in SEC's directory JSON to identify the primary Form 4 XML. Reasonable assumption. Wrong. The &lt;code&gt;type&lt;/code&gt; field in the production payload turned out to be display-class labels like &lt;code&gt;text.gif&lt;/code&gt;, not form codes. So my filter rejected every real filing on the first cron run. The corrected version matches by filename pattern (&lt;code&gt;ownership.xml&lt;/code&gt;, &lt;code&gt;primary_doc.xml&lt;/code&gt;, and a few legacy variants), then verifies by parsing and checking the &lt;code&gt;&amp;lt;documentType&amp;gt;&lt;/code&gt; element. Lesson: if you are integrating with a government API, do not trust your assumption about a field's semantics until you have seen the actual payload from production. I had three synthetic fixtures, all wrong about that field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel apex vs www domain redirect.&lt;/strong&gt; Spent an hour on a 308 redirect loop between &lt;code&gt;financepulse.app&lt;/code&gt; and &lt;code&gt;www.financepulse.app&lt;/code&gt;. The fix was to set the apex as the canonical and let Vercel handle the www-to-apex redirect at the platform level instead of trying to do it in a middleware. Boring, but I had not hit it before because all my other domains had been www-only from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hashnode AutoMod silent removals.&lt;/strong&gt; Two of the four platforms I am syndicating to (Bluesky, Mastodon, Dev.to, Hashnode) are reliable. Hashnode is the one I cannot fully trust yet. Twice now an article has shown a successful API response, then quietly disappeared from the feed within an hour. The article is technically live at the canonical URL, just delisted from discovery. No notification, no email. I am keeping the syndication for SEO link equity but I have stopped counting Hashnode reach in any metric that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is coming the next two weeks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tuesday Day 22, May 12.&lt;/strong&gt; First real FinancePulse digest sends. Same day, paid tier opens: $29 per-ticker report + $9 per month Pro subscription with watchlist and SMS alerts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Friday Day 25, May 15.&lt;/strong&gt; PatentScan landing page goes up. Free weekly USPTO grant digest in the same shape as FinancePulse, with a paid weekly deep-dive at $19 per report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 28, May 18.&lt;/strong&gt; Quick Start Guide v1.3, with a section on the multi-brand operator architecture I just described above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three brands, one operator, three different "what is the daily reason to come back" questions answered. If two of the three free digests retain readers at week 4, the playbook is real. If one of them does, I have a winner and two lessons. Either is fine. What is not fine is launching a fourth thing before I see what these do.&lt;/p&gt;

&lt;p&gt;If you want the free digest, it is at &lt;a href="https://financepulse.app" rel="noopener noreferrer"&gt;financepulse.app&lt;/a&gt;. One tap, no card, unsubscribe at the bottom of every email.&lt;/p&gt;

&lt;p&gt;If you want the operator playbook in long form, the &lt;a href="https://buildengine.tech" rel="noopener noreferrer"&gt;BuildEngine Quick Start Guide&lt;/a&gt; is $49 and has been the cleanest signal so far that the writing is doing its job. Buyers have come from articles, not ads.&lt;/p&gt;




&lt;p&gt;Build Wright&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>startup</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I open-sourced the Stripe webhook verifier I built for Next.js 15</title>
      <dc:creator>Build Wright</dc:creator>
      <pubDate>Wed, 06 May 2026 15:40:12 +0000</pubDate>
      <link>https://forem.com/buildwright/i-open-sourced-the-stripe-webhook-verifier-i-built-for-nextjs-15-3e6d</link>
      <guid>https://forem.com/buildwright/i-open-sourced-the-stripe-webhook-verifier-i-built-for-nextjs-15-3e6d</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;I shipped my first SaaS a few weeks ago. Stripe webhooks were one of the things that took longer than they should have, because the official Stripe documentation example breaks in Next.js 15 App Router.&lt;/p&gt;

&lt;p&gt;The issue is how App Router reads request bodies: The standard pattern in older Next.js used &lt;code&gt;req.body&lt;/code&gt; directly. App Router uses &lt;code&gt;request.text()&lt;/code&gt; and the body can only be consumed once, which trips up the standard Stripe verification flow if you read the body for any reason before passing it to the verifier.&lt;/p&gt;

&lt;p&gt;I solved it for myself, then realized other people were probably hitting the same wall. So I extracted what I built into a standalone package.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@northvane/stripe-webhook-verifier-nextjs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A type-safe Stripe webhook signature verifier for Next.js 15 App Router, with structured failure reasons so you can tell the difference between "wrong signature" and "expired timestamp" and "malformed header" without parsing error strings.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MIT license&lt;/li&gt;
&lt;li&gt;19 unit tests covering forged signatures, replay attacks, body tampering, malformed headers, edge cases&lt;/li&gt;
&lt;li&gt;Zero dependencies beyond the Stripe SDK (which you already have)&lt;/li&gt;
&lt;li&gt;Returns a typed &lt;code&gt;Stripe.Event&lt;/code&gt; on success, or a structured failure with a specific reason on failure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifyStripeWebhook&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@northvane/stripe-webhook-verifier-nextjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stripe-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;verifyStripeWebhook&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;signingSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRIPE_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Webhook error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// result.event is a typed Stripe.Event&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout.session.completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// handle&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common pitfalls this addresses
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Body parsing in App Router.&lt;/strong&gt; If you read &lt;code&gt;request.json()&lt;/code&gt; or &lt;code&gt;request.text()&lt;/code&gt; more than once, the second call returns empty. The package documents the right pattern.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stale signing secret rotation.&lt;/strong&gt; Stripe lets you rotate webhook signing secrets, but if you cache the secret in module scope, you keep verifying against the old one. The package recommends reading from env vars per-request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Timestamp tolerance defaults.&lt;/strong&gt; Stripe's default tolerance is 5 minutes, which protects against replay attacks. The package surfaces this as a structured failure (&lt;code&gt;reason: 'replay'&lt;/code&gt;) so you can log and alert separately from "wrong signature" failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documented quirk:&lt;/strong&gt; Stripe's tolerance check only rejects signatures from the past, not the future. Far-future timestamps pass verification. The package documents this so you're not surprised.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/aibuildwright/stripe-webhook-verifier-nextjs" rel="noopener noreferrer"&gt;https://github.com/aibuildwright/stripe-webhook-verifier-nextjs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Issues, PRs, and feedback welcome. This is the first of several utilities I'm extracting from my own SaaS launch and open-sourcing while building BuildEngine in semi-public.&lt;/p&gt;

&lt;p&gt;If you've hit similar webhook issues or are about to build your first Stripe integration, I'd love to hear what bit you.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Day 15: Why I Pivoted BuildEngine. The API Pricing Wall.</title>
      <dc:creator>Build Wright</dc:creator>
      <pubDate>Wed, 06 May 2026 03:13:25 +0000</pubDate>
      <link>https://forem.com/buildwright/day-15-why-i-pivoted-buildengine-the-api-pricing-wall-2k7n</link>
      <guid>https://forem.com/buildwright/day-15-why-i-pivoted-buildengine-the-api-pricing-wall-2k7n</guid>
      <description>&lt;h1&gt;
  
  
  Day 15: I already had to do a hard pivot. The API pricing wall.
&lt;/h1&gt;

&lt;p&gt;Two weeks ago I began the journey of BuildEngine. The goal was simple, to use AI tools to assist in building successful businesses, and to teach others how to do the same using my methods, lessons, and eventually software stack. Eleven days later I completed and posted BuildEngine's Quick Start Guide for sale. And the very next day I had to pivot the entire strategy.&lt;/p&gt;

&lt;p&gt;This is what happened…&lt;/p&gt;

&lt;h2&gt;
  
  
  The original plan
&lt;/h2&gt;

&lt;p&gt;Everything seemed very straightforward on paper. I would build AI-assisted business, document the journey along with every misstep, instruction, and correction, and then start with a $49 Quick Start Guide. Later, I would bring in subscription products: a $69/month "AI Business Operator" tier giving solo founders an inside look into how I am running my businesses and the strategies, revenue, and guidance that a multi-business dashboard and a set of comprehensive instruction doc would provide. Then, higher tier of "TractionKit", that would allow a solo founder to get multiple tools to run their businesses in a similar way.&lt;/p&gt;

&lt;p&gt;The operator tier was the entry point. Hey, I would run my own businesses with these tools, prove they work, then sell them to other solo founders for the same job. Build it, dogfood it, and then license them out to help others after showing that anyone can use AI to become a founder.&lt;/p&gt;

&lt;p&gt;However, the tools depended on several external data sources. Reddit for community engagement intelligence, ProductHunt for launch trend signals, and Twitter for engaging and building an audience.&lt;/p&gt;

&lt;p&gt;I had infrastructure assumptions for each of these, and they were all wrong. The big issue: I planned most of it with AI, and AI can (and will) make mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first wall
&lt;/h2&gt;

&lt;p&gt;Reddit's commercial API access requires written approval from Reddit for any commercial use, as opposed to earlier times where it was relatively open. I learned this on Day 14, after my new account got auto-removed from r/SideProject by Reddit's spam filter. I read the actual Data API Terms of Service for the first time. The clause makes it clear. And furthermore, the site doesn't even let you post until you build up a sufficient amount of karma.&lt;/p&gt;

&lt;p&gt;The application takes 1-7 days to review with no guarantees of success. ProductHunt's API requires similar approval. Both are explicit that "personal projects monetized later" still counts as commercial use, creating a massive stumbling block.&lt;/p&gt;

&lt;p&gt;Strike one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second wall
&lt;/h2&gt;

&lt;p&gt;No worries, I would just move to Twitter/X and get it done there. Right? A $100/month subscription tier gets you 60 search requests per 15 minutes, enough for my needs. Or at least Claude told me.&lt;/p&gt;

&lt;p&gt;So I went to register, and learned about a huge change in February 2026. Twitter killed all fixed cost subscription tiers. The new model is pay-per-use: $0.005 per post read, and $0.010 per post created. For my planned scope (scanning ~3,600 keyword searches per month plus polling 30 accounts at 5-15 minute intervals), the math works out to $750-1,000 per month.&lt;/p&gt;

&lt;p&gt;Son of a…!&lt;/p&gt;

&lt;p&gt;Now the unit economics were in the gutter. My Quick Start Guide is $49. I'd need 15-20 sales every month just to cover Twitter API calls alone, before any infrastructure/Claude/API costs, and to cover my time.&lt;/p&gt;

&lt;p&gt;And the real kicker is that I was relying on that as a sales channel to actually connect with potential customers! So paying such an amount to try to build audience, to try to make sales, to cover the API costs, make little sense.&lt;/p&gt;

&lt;p&gt;Strike two&lt;/p&gt;

&lt;h2&gt;
  
  
  The third wall
&lt;/h2&gt;

&lt;p&gt;I tried to fall back to the platforms where I could engage with no paid API. But of course Hacker News restricted Show HN posts on new accounts: "massive influx, become a contributor first." Indie Hackers requires a large comment history or a $198/year membership to post.&lt;/p&gt;

&lt;p&gt;Let's summarize: Twitter API priced me out. Reddit gated me out. ProductHunt gated me out. Show HN gated me out. Indie Hackers gated me out. Five distribution channels, all that I was counting on and would not be possible to use.&lt;/p&gt;

&lt;p&gt;Strike three.&lt;/p&gt;

&lt;p&gt;At this point, I realized I was out, and that I could either 1) give up or 2) pivot. Giving up is never an option.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reframe
&lt;/h2&gt;

&lt;p&gt;Here's what I thought about when trying to optimize around these constraints: Every solo founder hits this wall.&lt;/p&gt;

&lt;p&gt;Whether it is saturated channels, gated communities or the pain of shouting out into the void of a new Twitter account. APIs that used to be cheap and open are now expensive and closed. And paid ads on places like Meta and Google, well far too many solo founders have had negative ROI. The best platforms to use know that they are in a position of leverage, and have priced their tools and gated their walls (although the last is actually wise so AI bots don't run rampant). So ironically, the platforms that solo founders need to reach are the ones least open to new operators.&lt;/p&gt;

&lt;p&gt;The original BuildEngine would sell tools that work IF you have an audience. But solo founders without revenue can't afford the tools that build the audience.&lt;/p&gt;

&lt;p&gt;That gap is the actual product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pivot
&lt;/h2&gt;

&lt;p&gt;BuildEngine's product positioning is now: &lt;strong&gt;the Organic Distribution Stack for solo founders without paid ads.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same tools I was building for myself, which are now called Comment Interceptor, Cross-Platform Article Syndicator, AI Search Visibility Tracker, GitHub Marketing Engine, Direct Outreach Pipeline, Stack Overflow Answer Discovery, Press Outreach Pipeline, Schema.org auto-optimizer, have become the product. Not "automation for running an AI-assisted business." Instead, tooling for finding signal in saturated channels and amplifying organic reach without paid ad spend.&lt;/p&gt;

&lt;p&gt;The tools will work for any niche. I am dogfooding them across three brands simultaneously to prove this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;BuildEngine&lt;/strong&gt; (live) - solo founder tooling and methodology&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FinancePulse&lt;/strong&gt; (relaunching as free utility first) - insider buying signal aggregation for retail stock and financial investors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PatentScan&lt;/strong&gt; (new launch this month) - IP intelligence for legal and R&amp;amp;D professionals&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three different niches, three different audiences, one shared toolkit underneath. If the tools produce results in three unrelated categories, the value proposition is real. If they only work for one, I will learn something important and then decide if I need to drop one, start a new one, or do another pivot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built this week
&lt;/h2&gt;

&lt;p&gt;Even with the pivot, the week shipped. By Day 15:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick Start Guide v1.2 (77 pages, $49, live and selling on buildengine.tech)&lt;/li&gt;
&lt;li&gt;Comment Interceptor for HackerNews, running on a daily cron, with AI-scored opportunity surfacing in two modes: sales (high-intent buyer threads) and karma_building (substantive engagement opportunities)&lt;/li&gt;
&lt;li&gt;Schema.org structured data and llms.txt across the entire site, optimized for AI search assistant indexing&lt;/li&gt;
&lt;li&gt;This article syndicated to Bluesky, Mastodon, Dev.to, and Hashnode via the new Cross-Platform Article Syndicator (the article you are reading is the first real-world test of that tool).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What did NOT ship: Idea Validator (which was scheduled for May 7, has now slipped to mid-May for these unfortunate reasons), a Reddit version Comment Interceptor (waiting on commercial API approval), the TractionKit subscription product (now slated for week 6-8 after the tools are developed and tested for at least 4 more weeks).&lt;/p&gt;

&lt;h2&gt;
  
  
  What is coming
&lt;/h2&gt;

&lt;p&gt;The next four weeks of building will be, in rough order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finishing up the internal tools, testing them, and building them into a commercial product&lt;/li&gt;
&lt;li&gt;FinancePulse: free daily insider digest will launch publicly&lt;/li&gt;
&lt;li&gt;PatentScan: paid weekly USPTO grant digest will launch&lt;/li&gt;
&lt;li&gt;Day-by-day articles every 5-7 days documenting numbers, friction, and what I learned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll be honest, I felt like throwing in the towel for about 2 seconds. Just a moment of feeling sorry for myself before asking "how do I course correct." And that is what being a founder is all about.&lt;/p&gt;

&lt;p&gt;The Quick Start Guide is available for $49 now. TractionKit will open in about 6 weeks, with a special lifetime price for the first 25 customers when the tool launches.&lt;/p&gt;

&lt;h2&gt;
  
  
  On the pivot itself
&lt;/h2&gt;

&lt;p&gt;I was in a huge hurry to do month's worth of work in weeks and made a rookie mistake, namely forgetting to double check assumptions. Moving forward with a plan when assuming that certain tiers of pricing or API usage has remained constant, or posting permissions is available, was a complete and utter mishap on my part.&lt;/p&gt;

&lt;p&gt;But there is a silver lining here. I realized that any website can change TOS on you, increase their pricing or pull your access. So now BuildEngine is going to be very flexible, and is creating products that allow a solo founder to build without a large ad spend or API costs. That will be of tremendous value.&lt;/p&gt;




&lt;p&gt;Build Wright&lt;/p&gt;

&lt;p&gt;If you want updates on what I'm building, &lt;a href="https://buildengine.tech/subscribe" rel="noopener noreferrer"&gt;subscribe to the weekly brief&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>startup</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
