Action & questions
Everything unresolved, in one place. Cart opens Monday 17 Aug; only the organic funnel has to be live for it.
Uncommon team
Blocking Monday unless noted
- Terms content on
/aieb-tcLex · due EOD Sun 16The page exists and every checkout already links to it. It is empty. - Verify the domain for Apple PayLex or ChrisWhop dashboard → Settings → Checkout → Apple Pay for embedded checkout → Configure → Add payment domain, then follow the DNS instructions for
go.theuncommonbusiness.co. No domain is registered today, which is the only reason Apple Pay does not appear. - Bootcamp link added in FirstPromoterLisa · asked 14:42, no replyTracking is on every funnel and carries to checkout. There is no bootcamp link for a promoter to share.
- Order bump copyNickGA → VIP and VIP → Platinum. Defaults read "Upgrade to VIP" and "Upgrade to Platinum".
- Promo code namingLex · not blockingTest codes end in
TESTso Supabase archives them out of the launch numbers. Free and UCL codes need your convention so reporting splits.
Parisa
Whop side, in order
- Paste the six organic checkoutsTwo lines each. Ads funnel deferred to end of next week, per Lex.
- Live payment test, end to endOne pass covering Whop → GHL → n8n → Supabase → FirstPromoter. Must assert the sale lands against the promoter — a green checkout proves nothing about the affiliate chain.
- Answer Scott on the other webhooksRefund, cancellation, failed payment, dispute. He has the purchase payload already.
Open questions
Nobody has answered these yet
- How are free / UCL seats actually sold?A promo code, a separate checkout, or the existing $0 GHL form? Each needs a different fix and 400–600 members ride on it. A 100%-off Whop checkout is already handled; a $0 GHL form reaches nothing.
- Does a tripwire funnel exist?The workflows carry a tripwire condition and the Worker supports the value, but no tripwire funnel or page has been named.
- Do upgrade workflows need the n8n webhook?2a and 3a have never had one. The Worker now writes attribution before GHL sees the contact, and Supabase gets purchases straight from Whop.
- Who owns the Platinum seat cap?The plan reports unlimited stock, and the GHL counter has no trigger — it sits at 0, so the 180 / 195 alerts never fire. Nothing is counting right now.
- PayPal is not renderingEnabled in our config all day and connected on your side at 16:05, but the Whop account's capability list has no PayPal entry at all — only card, bank and BNPL. Activation on Whop's side, not configuration on ours. One for Ari.
- BNPL went active without a decision
accept_bnpl_paymentsflipped from inactive to active on the account this afternoon. Financing was never agreed for the bootcamp — the largest purchase here is $397. Our checkout still excludes it explicitly, so nothing changes at the till, but somebody turned it on.
The flow
One Worker sits between Whop and everything downstream. It knows what was bought at the moment of the charge, so nothing after it has to guess.
payment.succeededTier, cart, funnel, affiliate cookie and all five UTMs were stamped on before the charge.POST /contacts/{id}/workflow/{id}. A bumped cart enters two — base tier and upgrade.GHL workflows no longer decide anything about the purchase.
They branched on order amount to work out the tier. There is no GHL order now, so those branches read nothing. Emails, SMS, waits and tag conditions all stay — they just stop guessing.
Plans
Twelve live plans, all hidden from the storefront — reachable only through a checkout page. A price that steps on 20 Sep needs two plans, because a Whop plan carries one price.
| Plan | Price | Sells | Plan ID |
|---|---|---|---|
| Early Bird | $47 | to 13 Sep | plan_NWlCLuu4NotNr |
| General Admission | $97 | 13 Sep → close | plan_mtHkdjlQbvkHX |
| VIP | $197 | to 20 Sep | plan_vo09qNeR1gNKf |
| VIP | $297 | 20 Sep → close | plan_bgTK8oeOyv1up |
| Platinum | $397 | all launch | plan_pNNTBm1uvAmB4 |
| EB → VIP | $150 | to 20 Sep | plan_GzR4MwQNIv42l |
| EB → VIP | $250 | 20 Sep → close | plan_NjHgKCFXKRlzK |
| EB → Platinum | $350 | all launch | plan_f5bsCu7Z7iyrS |
| GA → VIP | $100 | 13–20 Sep | plan_MbBsqny6AWqxZ |
| GA → VIP | $200 | 20 Sep → close | plan_0XxN2EAjEKK7P |
| GA → Platinum | $300 | 13 Sep → close | plan_xiPbxrH89tmRU |
| VIP → Platinum | $200 | all launch | plan_RDxBErVUsQ3oB |
| VIP $297 → Platinum | $100 | on hold | not created |
VIP → Platinum, decided
Lex, 14 Aug: "VIP $197 → Platinum $397 = +$200. Once VIP increases to $297 (Sept 20) → Platinum $397 = +$100. For now, $200 increase is what it needed."
So the upgrade is priced off whatever VIP costs on the day. The $200 rung is live; the $100 rung gets built before 20 Sep. One consequence worth naming rather than discovering: a buyer who paid $197 for VIP in August and upgrades on 21 September pays $100 for a $200 gap. That is the accepted trade-off of pricing by date instead of by what they paid, and it keeps the offer simple to explain.
Every plan carries its own identifiers in Whop metadata — plan_key, offer, tier, is_upgrade, upgraded_from — so a payment can be traced back to exactly which rung was sold without a lookup table.
Affiliates
Sales reach FirstPromoter directly from the Worker. Eight GHL workflows are gone.
Capture
- FirstPromoter's tracking script is in the funnel head code and sets
_fprom_tid/_fprom_refongo.theuncommonbusiness.co. - The checkout block reads those cookies at load and sends them with the payment, so they arrive as Whop payment metadata and are reported with the sale.
- Cookies first,
?fpr=as fallback: the parameter only exists on the landing hop and is gone by the time most buyers reach checkout. - Same origin throughout, so the read works — provided FirstPromoter does not set those cookies
HttpOnly. Nothing can read an HttpOnly cookie from a page script. The live payment test is what proves this end to end, and it is the single most important thing that test checks.
What the eight workflows did
- Clear a field → write
{{order.total_price}}→ ×100 → POST the sale. - The first three steps existed only because GHL cannot multiply inline. The Worker holds cents already.
{{order.total_price}}does not exist without a GHL order, so those workflows are dead, not redundant.
Two fixes came out of it
- No more duplicate commissions. Every sale carries
event_id= the Whop payment ID. FirstPromoter requires it to dedupe; all eight workflows omitted it, so one retry paid twice. - Amounts were about to be 100× wrong. Whop reports dollars, FirstPromoter wants cents. Caught pre-launch.
One deletion still owed
- The
#2 Math operationstep in the eight FirstPromoter workflows. The Worker sends cents — leave it in and every sale reports at 100×.
Your side Tracking is on every funnel already and carries to checkout. Outstanding: add the bootcamp link to the promoter signup, so promoters have one to share.
Attribution
Organic, ads and tripwire are one attribute on the page. No logic to build.
- Each block declares
data-funnel="organic" | "ads" | "tripwire". It rides the payment; the Worker turns it into a tag. - New funnel page = copy the block, change
data-tieranddata-funnel. Nothing else. - Declared, not inferred, because two bootcamp funnels share one page URL.
- The exact page slug also lands in
aieb_page, so GHL conditions can target one ad page without a code change. - Tripwire is a real third value. GHL only ever wired ads and organic.
An upgrade never overwrites where the original sale came from.
What was there before. Every workflow ran an Ads / Organic / Tripwire block that read GHL's Funnel field and applied _organic or _ads. It ran on upgrade workflows too. So a buyer who came in through an ad and later upgraded on a page sitting in the organic funnel was re-tagged organic, and the ad lost the credit for a sale it had made.
What happens now. The Worker applies the funnel tag on a first purchase only, and skips it entirely when the offer is an upgrade. The original source survives. The upgrade is still fully recorded — aieb_page holds the exact page it was bought on, and the tier and path tags mark it as an upgrade — it just does not touch the attribution set on the first sale.
GHL changes
Tier workflows stay separate, one per tier. Each loses its payment trigger and its price branching, and keeps everything that speaks to the buyer.
The live set is the folder The AI Employee Bootcamp — WHOP: 1 — General Admission (Early Bird + GA), 2 - VIP, 2a — VIP upgrade, 3 - Platinum, 3a - Platinum upgrade, plus 4 - Bounce Email. All five are published and the Worker enters them by ID. The originals are untouched, kept only so the old build can be read side by side — sending a Whop buyer into one would re-run branches that read a GHL order amount that no longer exists.
Remove
- Every Payment received trigger — keys on a GHL order that no longer exists
- The price branch block and its tag nodes
- Ads / Organic / Tripwire, its three branches and two tag nodes
- The duplicate n8n webhook — keep one, on the main line
- Any Go to that only existed to rejoin a deleted branch
Keep
- Aevent, disable DND, the waits, Wisernotify
- Every SMS and email, and add-to-WF4
- The email-opened branch — engagement, not purchase
- Any branch reading a tag, prior purchase or contact state
- WF3's 180 / 195 Platinum seat notifications
Rule for anything ambiguous
Branch reads Amount, Workflow trigger or Funnel → delete. The Worker knows, and the branch now reads a value that never arrives.
Branch reads tags, prior purchases or email opens → keep. That is contact state and still works.
One addition per workflow: the n8n webhook's custom data gains whop_payment_id. It replaces ghl_order_id as the dedupe key and is the same value Supabase stores as processor_ref.
One exception: the Is Free? branch
- It reads Amount, so the rule says delete — but its output,
aieb-fall26_free, is how a free seat is identified downstream. The Worker does not write that tag today. - Unresolved until we know which route free seats take. See Action & questions.
Fields & tags
Written to the contact on every purchase, before any workflow runs.
| Field | Holds |
|---|---|
| whop_payment_id | The Whop payment. The join key across GHL, n8n, Supabase and FirstPromoter. |
| aieb_tier | ga · vip · platinum |
| aieb_offer | The exact rung, e.g. ga-to-platinum |
| aieb_funnel | organic · ads · tripwire |
| aieb_page | The page slug they checked out on |
| aieb_cohort | fall26 |
| promo_code | The code the buyer entered, if any. Stamped on the payment so a free seat is explicable by which code, not just by the amount being zero. |
| fp_plan | FirstPromoter plan string, for plan-level reward rates |
| fp_amount_cents | Sale amount in cents, stamped at charge time |
| firstpromoter_bid | Referral tracking ID, when there is one |
| utm_source … utm_term | All five, carried from the landing page |
Tags, in order
An upgraded buyer keeps the tag from the tier they started on as well as the one they moved to. Hub gating reads the entitlement; the dashboard reads the trail.
Checkout map
data-tier and data-funnel are the only two things that differ between one checkout and the next.
AI Employee Bootcamp — main funnel
| Page | Sells | data-tier | data-funnel |
|---|---|---|---|
| /general-admission-2026 | Early Bird $47 + 2 bumps | eb-ga,ga | organic |
| /vip-admission-2026 | VIP $197 + Platinum bump | vip | organic |
| /platinum-admission-2026 | Platinum $397 | platinum | organic |
| /vip-admission-upgrade | EB → VIP $150 | eb-ga-to-vip | organic |
| /platinum-admission-upgrade | EB → Platinum $350 | eb-ga-to-platinum | organic |
| /vip-platinum-admission-upgrade | VIP → Platinum $200 | vip197-to-platinum | organic |
| /bootcamp-2026-confirmation | Receipt block | — | — |
AI Employee Bootcamp Ads — rebuilt 15 Aug, new slugs
| Page | Sells | data-tier | data-funnel |
|---|---|---|---|
| /general-admission-2026-5280 | Early Bird $47 + 2 bumps | eb-ga,ga | ads |
| /vip-admission-2026-9281 | VIP $197 + Platinum bump | vip | ads |
| /platinum-admission-2026-9922 | Platinum $397 | platinum | ads |
| /vip-upgrade-eb-5042 | EB → VIP $150 | eb-ga-to-vip | ads |
| /vip-upgrade-g-2170 | GA → VIP $100 | ga-to-vip | ads |
| /bootcamp-2026-confirmation-2847 | Receipt block | — | — |
Source: live GHL funnel pull, 15 Aug 2026, 15:10 ET.
Two things to watch
Two ads funnels exist
- AI Employee Bootcamp Ads is the live one, rebuilt 15 Aug. 2026 - Bootcamp - ads has not been touched since May and still carries
/general-admission-2026-ads-checkout. Anything pointing at the old slugs is pointing at the wrong funnel.
Newsletter, advertorial, extended enrollment
- Still on the old checkout, so they sell nothing until a block is pasted. That is the tripwire route.
Pasted once, never again.
A page holds two lines — a <div> with its tier and funnel, and a script tag. Fields, bumps, summary, payment element, terms and button are all served by the Worker.
Wording and styling change in worker/src/copy.js, one wrangler deploy, all twelve checkouts at once. Prices, the terms link and the confirmation URL were already dynamic — all three changed today without touching a page.
The GHL page still owns the headline, body copy and images. Those stay editable in the page editor.
Editing the checkout
A checkout page holds two lines. Everything inside the block is served from one place, so a wording or styling change is one edit and one deploy — never twelve pages re-pasted.
What a page contains
| On the page | What it is |
|---|---|
| <div id="aieb-checkout" data-tier="…" data-funnel="…"> | Empty. Says which offer this page sells and which funnel it belongs to. The only thing that differs page to page. |
| <script src="…/embed.js" async> | Renders the whole block into that div: fields, bumps, order summary, payment element, terms, button, styling. |
Who edits what
Your team, in GHL — no deploy
- Headline, body copy, images, layout — everything around the block, edited in the page editor exactly as before
- Per-page wording overrides on the div:
data-cta,data-title,data-legend-order,data-legend-pay,data-terms-label,data-secure-note - Hide promo entry on one page with
data-promo="off". Hidden means not rendered — there is no field to type into and no code is sent.
Whop side — one deploy, all pages
- Wording inside the block, and the block's styling —
worker/src/copy.js - Hide promo entry on every page —
showPromo: falseincopy.js - Product names and bump labels —
worker/src/catalog.js - Prices, sale windows, plan IDs —
worker/src/plans.js
Three things were never on the page to begin with.
Prices, the terms link and the confirmation URL are all fetched from the Worker when the block loads. That is why the 13 Sep and 20 Sep price steps need no page edits at all, and why the terms link and confirmation URL both changed on 15 Aug without anyone opening a funnel.
Links
| What | Where |
|---|---|
| GHL workflows — the Whop set | The AI Employee Bootcamp — WHOP — all five rebuilt workflows plus WF4 |
| Main funnel | go.theuncommonbusiness.co/bootcamp-2026 — AI Employee Bootcamp, the one live on Monday |
| Ads funnel | go.theuncommonbusiness.co/ads-bootcamp-2026 — checkouts not swapped yet, due end of next week |
| Organic funnel — second | — to be confirmed |
| Tripwire funnel | — none named yet. See Open questions |
| Cloudflare | dash.cloudflare.com — account Hello@theuncommonbusiness.co |
| Code | github.com/whopio/aieb-fall26-whop-funnel — private. Send GitHub usernames to be added as collaborators. |
Where it runs
Everything is on your own Cloudflare account — Hello@theuncommonbusiness.co, account 81ac8dfc3cfa5c403247c595aef3db16. Nothing is hosted by Whop, so it stays yours at handover.
| Thing | Name | What it does |
|---|---|---|
| Worker | aieb-fall26-checkout | Serves embed.js and receipt.js, prices every cart, creates the payment, receives the Whop webhook, writes to GHL and FirstPromoter |
| Pages | aieb-fall26-handoff | This document |
Getting to it: dash.cloudflare.com → Compute (Workers) → aieb-fall26-checkout. Login credentials live in your password manager, never on this page.
What the dashboard gives you
- Logs — live request stream. Every payment, webhook and error as it happens.
- Deployments — every version, timestamped. One click rolls back to any earlier one, which is the fastest fix if something ships broken.
- Metrics — requests, errors, CPU time.
- Settings → Variables — the names of the stored secrets. Values are write-only and cannot be read back, by anyone.
What it does not give you
- Editing the checkout. Wording and styling live in the repo, not the dashboard — changing them means an edit plus
wrangler deploy, which is a different credential from the Cloudflare login. - Cloudflare access is for watching and rolling back. Changing is a code change.
Source
github.com/whopio/aieb-fall26-whop-funnel — private. Send the GitHub usernames who need it and they will be added as collaborators.
Everything is in there: the Worker, the generated checkout blocks, the GHL inventory scripts and this document. No secrets — env/.env is gitignored and the Worker's credentials are stored in Cloudflare, write-only.
Deploying a change
| Step | Command |
|---|---|
| 1. Check | node scripts/check-embed.mjs — compiles the exact script the browser will receive |
| 2. Deploy | cd worker && npx wrangler deploy |
| 3. Confirm | node scripts/check-embed.mjs --live — checks what production is now serving |
Step 1 is not optional. embed.js is generated, so the source file can be valid while the string it produces is not — that took every checkout down silently on 15 Aug, with a blank space where the form should be and nothing in the console.
Supabase
Scott's n8n endpoint receives the purchase and writes to Postgres directly. Whop points at it; nothing of ours sits between.
- That keeps
salesprivate — reaching it over the API would have meant exposing all 17 tables for one insert. - Failures land in n8n's execution history with alerting already attached.
- Rows land as
processor = 'whop',processor_ref= the Whop payment ID — the same shape as the 25,000 GHL rows, so reporting spans both.
One payment can hold two products
A plan is one product at one price — that never changes. But an order bump is one payment carrying two of them: Early Bird $47 plus the VIP upgrade $150, charged once as $197.
Whop's payments API takes a single plan with a single price and has no line-item array, so the parts cannot be expressed as plan IDs on the charge itself. They ride in the payment metadata instead, as three parallel comma-separated lists in line order, base first:
| Metadata key | Example — Early Bird with the VIP bump |
|---|---|
| plan_ids | plan_NWlCLuu4NotNr,plan_GzR4MwQNIv42l |
| plan_keys | eb-ga,eb-ga-to-vip |
| line_amounts | 4700,15000 — cents |
| offer | eb-ga+eb-ga-to-vip — the whole cart as one string |
| tier | vip — what they ended up entitled to |
| promo_code | The code used, if any. Identifies a comp seat by which code rather than by the amount being zero. |
One row per entry, resolved by plan ID. That is the same two-row shape a GHL multi-line order already produces against one processor_ref — the 539 pairs already in purchases. A single-item cart is a list of one, so it stays one code path. The idempotency key needs to include the plan ID to keep both rows.
Plan map
Twelve live plans. All hidden from the storefront, reachable only through a checkout.
| plan_id | plan_key | tier | price |
|---|---|---|---|
| plan_NWlCLuu4NotNr | eb-ga | ga | $47 |
| plan_mtHkdjlQbvkHX | ga | ga | $97 |
| plan_MbBsqny6AWqxZ | ga-to-vip | vip | $100 |
| plan_GzR4MwQNIv42l | eb-ga-to-vip | vip | $150 |
| plan_vo09qNeR1gNKf | vip | vip | $197 |
| plan_RDxBErVUsQ3oB | vip197-to-platinum | platinum | $200 |
| plan_0XxN2EAjEKK7P | ga-to-vip-late | vip | $200 |
| plan_NjHgKCFXKRlzK | eb-ga-to-vip-late | vip | $250 |
| plan_bgTK8oeOyv1up | vip-late | vip | $297 |
| plan_xiPbxrH89tmRU | ga-to-platinum | platinum | $300 |
| plan_f5bsCu7Z7iyrS | eb-ga-to-platinum | platinum | $350 |
| plan_pNNTBm1uvAmB4 | platinum | platinum | $397 |
Changed since the 15 Aug plan pull
Twelve plans, not eleven
plan_RDxBErVUsQ3oB— VIP → Platinum, $200 — was created on 15 Aug. An upgrade on it hits an unmapped ID until it is added.
Two plans were deleted
plan_PM6BnVHX9s1VQandplan_zYXcUq9PqjfUYwere duplicates with metadata that entered no GHL workflow. Drop them if they were picked up.
The three -late IDs are real
- They map to the same tiers as their non-late counterparts, but they are distinct plan IDs and go live on 13 and 20 Sep. A map keyed on plan ID needs entries for them.
Other webhooks
Only payment.succeeded points at n8n today. Refunds, failed payments, cancellations and disputes each have their own event at dev.whop.com. Refunds are the one that matters before launch — without it a refunded seat still counts as sold.