← blog.buildwithjz.com

The Day I Found Out Nobody Could Actually Get the Products I Was Selling

2026-04-22 · MoneyMachine

The Day I Found Out Nobody Could Actually Get the Products I Was Selling

Short version: my 21-agent AI factory had built five info products, deployed five landing pages, and created five Stripe payment links at €29-€49. Then I opened one of them and asked a dumb-sounding question: “where does the buyer actually get the product after they pay?”

The answer, over the next four hours: they don’t. They would pay €39 and receive nothing except a Stripe receipt. And that wasn’t even the worst problem.

I’m writing this because the failure mode here isn’t a bug in any single agent. It’s something I’ve been calling a factory-design miss: the DIRECTIVES I wrote for my agents told them to build products, deploy landing pages, and create checkout links. They did exactly that. Nothing said “and make sure the buyer can download the thing they paid for.” So no agent did that. They can’t — they have no imagination outside their instructions.


What I thought was shipped

Before tonight, I believed five products were ready for marketing:

  • AEO Starter Kit — €39
  • AI Visibility Audit Playbook — €39
  • MCP Security Hardening Guide — $29
  • Creator Revenue Independence Kit — €39
  • Freelancer AI Pivot Playbook — €39

Each one had a live landing page at <slug>.buildwithjz.com. Each had a Stripe payment link. My CEO agent (“Adrian”) had marked them all as “approved” and “live” in the product pipeline. Revenue Ops was monitoring Stripe for charges.

I asked a basic operator question: “Where can I see the landing pages? Does the dashboard show the URLs?”

The dashboard didn’t have them (separate bug I won’t get into here — the products_pipeline.domain column was empty for every live row, and the dashboard was only hardcoded to show one URL from a month ago). So I pulled the URLs directly from the Cloudflare Pages API and visited the sites.

Here’s what I saw.

On aeo-starter-kit.buildwithjz.com, midway down the page, I saw this:

Checkout

Replace with checkout link before publish:

https://buy.stripe.com/fZu4gAgef9pe0wy6hfbEA03

Literal placeholder text. Visible to anyone visiting the page. A buyer would see “Replace with checkout link before publish” — with no action taken. The actual Stripe URL was there as a code block, not a clickable button.

I thought this was just a Builder oversight. It turned out to be deeper.

Failure 2: Five days of preview deployments

When I pulled the source for the aeo-starter-kit page from the Builder’s workspace, the placeholder was already removed. Someone (a Builder run) had fixed it yesterday. But the live site still showed it.

I was staring at a 5-day-old version of the page.

Root cause: Release Engineer’s deploy script was running wrangler pages deploy . --project-name aeo-starter-kit. Without the --branch main flag, wrangler defaults to master. In Cloudflare Pages, master is the preview environment — it does NOT serve the custom domain. The main branch serves aeo-starter-kit.buildwithjz.com.

Release Engineer had been “successfully deploying” for five days. Every one of those deploys became a preview. The actual custom domain — the thing buyers hit — was still pinned to the last deploy that landed on main, which was on April 18th. So the placeholder text had been removed from source, redeployed dozens of times, and stayed live on production.

I fixed it in one line: pass --branch main. Then I promoted all five products’ latest preview deploys to production. The placeholder disappeared.

So far: two bugs, both fixed. I thought I was done.

Failure 3: Nobody gets the product

Then I asked: “where can I see the actual digital product we’re selling?”

I went to look at what was “inside” the AEO Starter Kit. I found:

/home/agentops/.openclaw/workspaces/builder/projects/aeo-starter-kit/
├── landing/          ← the marketing page (deployed)
├── src/
│   ├── product-guide.md     ← 458 words of markdown
│   └── README.md            ← "delivery guide"
├── templates/
│   ├── aero-content-template.md (578 bytes)
│   ├── ai-query-audit-matrix.csv (639 bytes)
│   ├── aiprompt-clarity-cards.md (549 bytes)
│   ├── answer-engine-positioning-checklist.md (674 bytes)
│   └── weekly-aeo-tracking-dashboard.md (573 bytes)
└── tests/            ← unit tests for the validation code

Total “product” content: about 3 KB of markdown files. Priced at €39.

Now I asked the real question: “how does the buyer receive these files after they pay?”

I checked the Stripe Payment Link via the API:

{
  "after_completion": {
    "type": "hosted_confirmation",
    "hosted_confirmation": {
      "custom_message": null
    }
  }
}

custom_message: null.

Stripe has three ways to handle post-purchase delivery on Payment Links:

  1. hosted_confirmation with a custom_message — shows a success page with whatever you write in the message field (supports markdown, includes links)
  2. redirect — sends the buyer to your URL
  3. Default — just says “Payment received”

We had #3. Our default. A buyer would click “Pay €39”, enter their card, see a Stripe success screen that said “Your payment was received”, get a receipt email from Stripe confirming they’d been charged, and that would be it. No download link. No email with files. No redirect. No member portal. Nothing.

They would never receive the product they paid for.

Across all five products. Every one of them. Zero delivery.

Failure 4: Raw markdown isn’t a deliverable anyway

Even if we fixed the delivery mechanism, what would we actually deliver? A ZIP of markdown files. Buyers of a €39 info product expect:

  • A PDF (pretty, printable, shareable)
  • OR a Notion doc (clickable, workable)
  • OR at minimum, a single consolidated guide, not 5 template files scattered around

They would open their download and find .md files they’d need to view in VS Code or a text editor. That’s a credibility-killer for a paid product even if every other thing was perfect.

Failure 5: The content was thin

While I was reading the products, I measured them:

ProductMain guide wordsPrice
AEO Starter Kit458€39
AI Visibility Audit Playbook386€39
MCP Security Hardening Guide256$29
Creator Revenue Independence Kit404€39
Freelancer AI Pivot Playbook249€39

Four of five products had under 500 words in the main guide. At €39, that’s less than 8 words per cent. A long Twitter thread gives buyers more. The content wasn’t slop — the frameworks were real, the safety language was appropriate — but it was insultingly thin for the price.

The stack of five failures

Let me zoom out. What a buyer would have experienced if they had bought yesterday:

  1. They visit aeo-starter-kit.buildwithjz.com and see “Replace with checkout link before publish” text. Half of them close the tab. (Failure 1, Failure 2.)
  2. The half that push through click the Stripe link and pay €39.
  3. They see Stripe’s generic “Payment received” page with no next steps.
  4. They check their email. One receipt, no download link, no instructions.
  5. They email hello@withjz.com asking “where’s my product?”
  6. If we manually fulfill, they open a ZIP of raw markdown files and feel ripped off.
  7. They refund within 24 hours.

100% refund rate. Zero repeat customers. Probably a Stripe dispute or two.

And none of my AI agents noticed. Because none of them were instructed to.

The fix — 7 hours

I kicked off a /loop with my Claude Code session — dynamic self-pacing, four explicit phases — and went offline for a few hours. Here’s what shipped by morning:

Phase 1: Wire Stripe delivery for every product.

For each of the five Stripe Payment Links, I used the Stripe API to set after_completion.type to redirect and pointed it at a Cloudflare Pages Function at <slug>.buildwithjz.com/delivery?session_id={CHECKOUT_SESSION_ID}. When a buyer completes checkout, Stripe substitutes their session ID and sends them to the Function, which:

  1. Verifies the session exists in Stripe and has payment_status: paid
  2. Confirms the session bought THIS product (checking line_items against product_id)
  3. Shows a success page with a download link to a ZIP at a long-random URL path
  4. If the URL is visited without a session_id, it shows a recovery form where the buyer enters their email and the Function searches Stripe for their purchase and serves the link again

No new paid services. The Function runs on Cloudflare’s free tier. The Stripe verification is free (read-only API calls). Lost-link recovery works without building an email system.

Phase 2: Package each product as a real deliverable.

For each product, I used pandoc with xelatex to generate a PDF from the main guide. Added a title page with “Published by withJZ — Jeff & Zachary” and the date. Embedded the templates as a formatted appendix. Built each product as a ZIP containing:

  • <slug>.pdf — polished guide, clickable links, proper typography
  • product-guide.md — source for power users
  • templates/* — all templates, ready to copy into Notion / wiki
  • README.md — a welcoming note, how to use, support, refund policy

Deployed each ZIP to the respective Pages project on main branch at a non-guessable token path.

Phase 3: Double the content depth.

For each product, I wrote (or had an expansion generated based on the existing framework) four new sections:

  • A Worked Example — 400-800 words showing a named realistic persona applying the framework end-to-end across multiple weeks. “Anna, B2B SaaS founder auditing ChatGPT mentions for Cohortly.” “Marcus, 82k-sub YouTuber moving off platform dependence.” “Priya, indie dev auditing MCP servers across three IDEs.” Worked examples are the highest information density per word in any info product.
  • Common Mistakes — 5-6 concrete failure modes to avoid
  • Quick-reference FAQ — 5-6 Q&A pairs that preempt real buyer questions
  • Template walkthrough — one template in before / after form showing what a completed row looks like

Word count before and after:

ProductBeforeAfterChange
AEO Starter Kit4581,560+240%
AI Visibility Audit Playbook386854+121%
MCP Security Hardening Guide2561,284+402%
Creator Revenue Independence Kit404951+135%
Freelancer AI Pivot Playbook2491,483+496%

All five now have the Worked Example, Mistakes section, FAQ, and Template walkthrough. Four of five are over 1,000 words. The thinnest is still 854 — not where I want it long-term but defensible at a price adjustment.

Phase 4: Write DIRECTIVES so this can’t happen again.

This was the most important phase. My Builder DIRECTIVES had 37 lines. My Adrian DIRECTIVES had a “Quality Gate” section that said essentially “check each deliverable for quality.” Neither specified how. Neither required delivery wiring. Neither required content depth. Neither enforced production-branch deploys.

I rewrote Builder DIRECTIVES from 37 to 163 lines with 7 explicit pre-publish quality gates:

  1. Content depth (≥1,000 words for €39+, with mandatory sections)
  2. Templates have worked examples (not blank)
  3. Landing page has zero placeholders (grep check before approval)
  4. Delivery mechanism wired (with the exact curl recipe in the DIRECTIVES)
  5. Polished deliverable (PDF + bundle, ZIP ≥40 KB)
  6. Deploy to main branch (not master — references this incident by name)
  7. Smoke test post-deploy (three specific curl checks)

I added a new Section 5a to Adrian DIRECTIVES: Product Approval Checklist (MANDATORY). Ten gates, each with the exact command Adrian runs to verify. No more approving on Builder’s word. Adrian runs sudo wc -w, curl | grep, curl https://api.stripe.com/v1/payment_links/... himself. If any gate fails, it’s an automatic REJECT with a numbered list of what needs fixing.

The lesson

None of my agents were lazy. None of them were incompetent. None of them hallucinated.

Builder built exactly what it was asked to build: a landing page + a checkout link + some templates + some tests. The DIRECTIVES said “build info products” and Builder did. The DIRECTIVES said “create a Stripe payment link” and Builder did. No line in any DIRECTIVES said “wire post-purchase delivery” — so no agent did.

Release Engineer deployed exactly what it was asked to deploy: it ran wrangler pages deploy. The command without --branch main defaults to master. Nothing in the DIRECTIVES mentioned the distinction. Release Engineer kept “deploying” and marking runs as successful.

Adrian approved exactly what he was asked to approve: Builder’s handoff document said “product is complete.” Adrian scored quality ≥8 based on “this looks done.” The DIRECTIVES said to check quality, not to verify delivery, not to visit the live URL, not to open the Stripe Payment Link config. So Adrian didn’t.

AI agents build what the DIRECTIVES tell them to build. Nothing more. The DIRECTIVES are the assembly line. Every tolerance, every check, every blocker that exists in a human engineering organization as “common sense” or “the way we do things” has to be written down for an agent. If it isn’t written, it doesn’t exist.

This is obvious in retrospect. But it’s easy to forget when the agents are producing outputs that look complete. Buildings have load-bearing walls. Spreadsheets have validation rules. Software has tests. AI factories have DIRECTIVES. You can’t ask an agent to have judgment; you can only ask them to follow rules. And the rules have to cover every integrity boundary of the system.

Revenue update

Zero customers yet. Zero refunds yet — because the failures above hit after money was taken. The fact that this got caught with zero customers is the one piece of luck in this story.

Most info-product startups discover this kind of thing after their first three chargebacks. I found it by asking two questions at 10 PM on a Wednesday. The questions were “where does the product get delivered?” and “did anyone QA these?” Those questions are now explicitly in Adrian’s Section 5a as Gates 4 and 5. They’ll never need to be asked by a human again — assuming the DIRECTIVES are followed.

What to watch for

If you’re running an AI-agent-based production system, or thinking about building one, ask yourself:

  • What is the minimum integrity boundary of my product? For us it’s: money changes hands → buyer receives product. Every assembly step between those two endpoints is a potential failure point.
  • Is every integrity check written as a DIRECTIVE gate, not assumed? If your human engineers would do it as “common sense,” your agents won’t do it at all.
  • Does your CEO agent verify, or does it rubber-stamp? Rubber-stamping is the default unless you write the specific commands that constitute verification.
  • Would a fresh pair of eyes catch this in five minutes? If yes, your factory’s introspection is weak. Add monitoring until the fresh pair of eyes is an automated alert.

I’m still here, I still believe in the approach, and the factory is materially stronger tonight than it was this morning. But this one was on me — not on the agents. I wrote the DIRECTIVES. They built exactly what I specified. Next time I’ll specify more.

Good luck to anyone running a similar experiment. Tell me what your version of Gate 5a looks like — I want to compare notes.

— Jeff


Back to index