About That — real-estate paid launch
How to turn on the About That real-estate paywall. Built dark 2026-07-17 (PR pending); mirrors the EMBERKILN_PAID_LAUNCH.md flag-gated pattern.
The model
- Only the
agent/Open-House preset is paid ($79/mo Agent, $399/mo Brokerage).founderandcandidate(job-seeker) presets are always free — the funnel. An agent's free bio page just uses a free preset. - Dark by default: the whole gate is behind
NEXT_PUBLIC_ABOUT_THAT_PAID_MODE. While unset/false, nothing is gated — About That behaves exactly as it does today. Flip totrueonly after the Stripe prices exist. - Gate is at RENDER, not create: owners can build + configure an agent embed, but the spend paths (rendition, FAQ) return 402 and eager render skips silently until the owner subscribes. So flipping the flag never hard-breaks a configured embed — it shows the upgrade CTA.
One-time setup
- Create two recurring Stripe prices in your Stripe dashboard:
- Agent — $79/month
- Brokerage — $399/month
- Set the price env vars (Railway backend + Vercel frontend both read
Railway-provided vars):
Until these are set,STRIPE_PRICE_ABOUT_THAT_AGENT=price_... STRIPE_PRICE_ABOUT_THAT_BROKERAGE=price_...POST /api/payment/about-that/checkoutreturns 503 (same as Graphene+). The webhook already activates them viapriceToPlanKey. - Flip the master switch when ready to charge:
Redeploy. Agent-preset embeds now require an active plan; the dashboard shows the "$79/mo" upgrade CTA on agent embeds;NEXT_PUBLIC_ABOUT_THAT_PAID_MODE=true/about-that/for-real-estateshows live pricing.
How activation works (no new code)
Checkout (/api/payment/about-that/checkout {plan:'agent'|'brokerage'}) →
Stripe subscription → the existing POST /api/payment/webhook upserts a row
into subscriptions with plan_key about_that_agent / about_that_brokerage
(mapped by priceToPlanKey). isAboutThatSubscriber(userId) reads that row.
Management uses the existing /api/payment/customer-portal.
Comping a user (e.g. Ryan's 90-day design-partner deal)
No Stripe charge needed — insert an active subscription row directly:
insert into subscriptions (user_id, plan_key, status, current_period_end, cancel_at_period_end)
values ('<user-uuid>', 'about_that_agent', 'active', now() + interval '90 days', true);
cancel_at_period_end = true + a future current_period_end = access until it
lapses, then it naturally closes (they convert or the gate returns).
Code map
- Gate + flag + subscriber check:
services/about-that-billing.ts(shouldGateRenderis the pure, unit-tested decision). - Enforcement (402 render/FAQ, eager skip):
services/about-that.ts. - Checkout + plan-key map:
routes/payment.ts. - Status endpoint:
GET /api/about-that/billing/status. - Dashboard CTA:
dashboard/about-that/page.tsx; pricing:about-that/for-real-estate/page.tsx.