zsty.us

Before / After · Case Study

Big Moose Hemp — card payments with a hard ceiling and a bank-transfer lane for big orders

  • Hemp / CBD
  • Local Pro Services

Big Moose Hemp took every payment through a single card lane on their old website platform — no spending rules, no fallback, in an industry where card processors get nervous. Now everyday orders go on cards under a hard $250 ceiling, bigger purchases move by bank transfer automatically, and the store can switch card processors without ever going dark.

Belt and suspenders — the card cap is enforced in three places so neither the admin nor the API can bypass it.

At a glance

What this rebuild covers.

  • Selling & payments

    Two ways to get paid under one roof — cards for everyday orders, bank transfer for anything bigger, chosen automatically at checkout by order size.

  • Selling & payments

    Settlements and refunds from both payment lanes land in one reconciliation view, so the owner checks one ledger instead of two dashboards.

  • Security

    The hard $250 card limit is enforced in three separate places, so no path — not even a manual admin order — can push a bigger charge onto a card.

  • Security

    Every settlement and reversal message from the payment networks is signature-checked before it touches the books.

  • App builds

    Payment rules live on an admin screen the owner can change in seconds — including an instant off-switch that takes card payments offline without a developer.

Receipts — measured

Numbers that moved.

1
Payment rails under one Medusa module
was 1
0
Cap-enforcement layers (module + API + storefront)
was 0
0 $
Hard card cap
was 0 $
0
Webhook reconciliation surfaces
was 0
  • 1 payment lane → 2
  • $250 card ceiling, enforced 3 ways
  • Big orders auto-route to bank transfer
  • Cards can be switched off in seconds

The story

Problem · Insight · Build · Outcome.

  1. 01 · Problem

    High-risk MID on a vendor stack that doesn't expose payment policy.

    Hemp/CBD is a high-risk merchant category. The legacy WIX-PAY-PRO + Square stack didn't expose payment-policy controls, didn't have an ACH fallback for over-cap purchases, and didn't allow swapping rails without rebuilding the storefront. With the federal hemp ban accelerating, the platform needed payment infrastructure that could survive a rail change without going dark.

  2. 02 · Insight

    Move the policy into the platform, split the rails by amount.

    Card processing is fine for the long tail of small orders — under $250. Above that, ACH is cheaper, doesn't burn the card MID's risk budget, and matches how bulk clone deposits actually flow. The fix is a two-rail Medusa module where the cap is platform policy, not vendor policy — enforced in three places so no path can bypass it.

  3. 03 · Build

    Two payment provider modules + a policy endpoint, all under the Medusa 2.x contract.

    `backend/src/modules/payment-clover/index.ts` (Clover Ecomm SDK via GPS ISO) and `backend/src/modules/payment-aeropay/index.ts` (Aeropay bank-linked ACH). Each implements the Medusa 2.x payment provider interface — initiate, authorize, capture, refund, cancel, retrieve, webhook. The Clover module enforces the card cap in `authorize()`; the storefront enforces it again in `/api/checkout`; the admin surfaces it via `/admin/settings/payment-policy`. A sandboxed merchant account is wired for Clover dev.

  4. 04 · Outcome

    A payment surface that survives a rail change without going dark.

    Card-rail vendor changes are a feature flag flip. ACH stays put. Webhook reconciliation lands in one view. The same module pattern is reusable across BMH, Buck Mountain, and any other brand that needs the high-risk MID + ACH-fallback split — which is most of the cannabis/hemp portfolio.

  5. 05 · Pending

    Open work tracked at CODEX_HANDOFF.md #17.

    Both modules ship the contract surface with TODO(#17) on the actual provider integration. Clover sandbox account is wired; production credentials gated on the GPS ISO onboarding completing. Aeropay sandbox URL switching is wired; bank-linked pull testing pending account approval. Until then the storefront falls back to manual ACH instructions for over-cap purchases.

For the technically curiousHow it was done
  1. 01

    Where it started

    Payments ran through Wix's payment layer plus Square. Hemp/CBD is a high-risk merchant category, and that stack exposed no payment-policy controls: no spending caps, no ACH fallback for larger purchases, no admin surface for payment rules, and no webhook handling for reconciliation. Everything hung off a single card lane the store didn't control.

  2. 02

    Why it had to change

    A federal hemp law taking effect in late 2026 re-classifies most of the catalog, which means the card processor behind the store may have to be swapped. On the old stack, a processor change meant rebuilding the storefront. The store needed payment infrastructure where the rails are interchangeable and the policy belongs to the platform, not the vendor.

  3. 03

    The rebuild

    Two payment modules were built inside our commerce engine, both implementing the same provider contract — initiate, authorize, capture, refund, cancel, retrieve, webhook. One is a card lane through a processor set up for the high-risk merchant category, hard-capped at $250 per charge. The other is a bank-transfer (ACH) lane that takes any purchase over the cap and the 50% deposits on large bulk orders. Together they expose a 13-method contract surface, with sandbox and production endpoints switchable per environment.

  4. 04

    The guardrails

    The $250 card cap is enforced at three levels: inside the card module itself (which rejects any over-cap authorization), again at the checkout API, and again on the admin payment-policy screen — belt and suspenders, so no route can bypass it. Over-cap orders route to the bank-transfer lane automatically. A kill-switch flag takes the card lane offline instantly, and the storefront falls back to bank-transfer-only checkout on its own. Webhook events from both lanes are signature-verified and fed into the order-state machine, so settlement and reversal reconcile in one view.

  5. 05

    What runs now, and what's next

    The full contract surface is shipped with sandbox wiring for the card lane; production credentials are gated on the processor's onboarding finishing, and bank-transfer pull testing is pending account approval. Until then, over-cap purchases fall back to manual bank-transfer instructions. The architecture is deliberately rail-agnostic: when the federal change lands, swapping the card processor is a one-line configuration change — the bank-transfer lane, the cap, and the reconciliation view all stay put. The same pattern is reusable across the rest of the cannabis/hemp portfolio.

Architecture

Old stack
  • Wix payments
  • Square (single MID)
  • No ACH fallback
  • No cap enforcement
  • No admin policy
New stack
  • headless commerce engine
  • payment-clover (card ≤ $250)
  • payment-aeropay (ACH > $250)
  • /admin/settings/payment-policy
  • HMAC webhooks (settlement + reversal)
  • Three-level cap enforcement
  • Feature flag toggle

What changed, with evidence

Agent backbone

Two-rail abstraction — card under the cap, ACH over

`payment-clover/index.ts` and `payment-aeropay/index.ts` both implement the Medusa 2.x payment provider contract. The card rail (Clover Ecomm SDK via Global Payments Solutions ISO) handles tokenize → auth → capture → refund → void → status sync → webhook decode. The ACH rail (Aeropay) handles the bank-linked pull (1-2 business days) → settlement → reversal — used for any card-over-cap purchase and for the 50% deposit on the 500+ clone Standard-tier orders.

Before
Single payment surface inside Wix — no rail switching, no cap enforcement, no admin policy.
After
Two independent rails under one Medusa module, swappable per order amount, with a single admin policy endpoint.
  • Clover: 7-method contract (initiate, authorize, capture, refund, cancel, retrieve, webhook)
  • Aeropay: 6-method contract (initiate, authorize, capture-n/a, refund, retrieve, webhook)
  • Both modules expose sandbox vs production URLs via environment switch
  • A sandboxed merchant account for Clover dev
Agent backbone

Hard cap at three levels — belt and suspenders

The $250 card cap — a hard spending cap adjustable without a code change — is enforced in the Clover module's `authorize()` (rejects any over-cap call), in the `/api/checkout` storefront API, AND in the `/admin/settings/payment-policy` surface. No path — including admin-authed manual orders — can route a card charge above the cap. Above-cap orders automatically route to the Aeropay ACH rail.

  • Module-level: payment-clover rejects authorize() with amount > cardMaxCents
  • Storefront: /api/checkout enforces the same cap before calling the provider
  • Admin: /admin/settings/payment-policy returns the cap + ACH-required-above flag
  • A kill-switch flag gates the card rail entirely
Agent backbone

Reconciliation by webhook — settlement + reversal land in the same surface

Both rails publish settlement + reversal events. Clover's `getWebhookActionAndData()` verifies the HMAC + decodes the event into a typed action; Aeropay's webhook handles settlement + reversal asynchronously. Both feed back into the Medusa order-state machine so the operator sees one reconciliation view, not two.

Retention

Designed to swap rails as the federal hemp ban hits

The architecture is rail-agnostic on purpose. As P.L. 119-37 (Nov 12 2026) re-classifies most of the current catalog, the storefront swaps from `payment-clover` (high-risk hemp MID) → `payment-stripe` (compliant wellness MID) by changing one provider registration in `medusa-config.ts`. ACH stays on Aeropay throughout.

While the owner sleeps.

Autonomous surfaces

The agent backbone keeps the brand earning after hours. The owner approves; the system runs.

  • Routes payments by amount, not by operator choice

    on every checkout

    Storefront and admin both consult the payment-policy endpoint; over-cap purchases auto-route to ACH without operator intervention.

  • Reconciles webhook events into the Medusa order-state machine

    real-time on each event

    Settlement + reversal events from both rails land in the same operator surface — no separate dashboards.

  • Gate-flips the card rail without a redeploy

    instant on env flip

    Flipping the kill-switch flag off takes the card rail offline immediately; storefront automatically presents ACH-only checkout.

← All rebuilds

Big Moose Hemp — card payments with a hard ceiling and a bank-transfer lane for big orders — zsty.us