Stripe live-mode cutover runbook
When Mercury account clears (~Monday 2026-05-04 / Tuesday 2026-05-05) and we're ready to flip to live mode, follow these steps. Sandbox-mode setup completed 2026-05-03 and the live-mode setup follows the same pattern with new IDs.
Pre-flight (Mercury-side)
- [ ] Mercury OBB Holdings account funded + accessible
- [ ] OBB Holdings EIN documented in Stripe live tax settings
- [ ] OBB Holdings WI state registration confirmed available for ToS
Stripe live-mode setup (~30 min keyboard time)
- Toggle Stripe to live mode in dashboard (Test → Live switch top-right)
- Run setup script at
/Users/lukeolson/discord-bot/_scripts/stripe_live_setup.py (TODO: build by porting the API calls from this conversation, replacing STRIPE_SECRET_KEY_TEST with STRIPE_SECRET_KEY_LIVE):
- Creates HF Floor product + $9,900/mo recurring price
- Creates HF Overage product + graduated tiered metered price
- Creates
hf_completed_appeal Billing Meter
- Outputs new live-mode IDs to
stripe_hf_objects_live.json
- Connect Mercury as payout destination:
- Stripe → Settings → External payouts → Add bank account
- Plaid OAuth (search "Mercury") OR manual routing + account number from Mercury dashboard
- Verify via micro-deposits (~1-2 business days)
- Configure live webhook endpoint:
- Register
https://obb-stripe-webhook.pages.dev/stripe in live mode
- Copy live
whsec_* → set as Pages Project secret STRIPE_WEBHOOK_SECRET_LIVE
- The Pages function already routes test vs. live by event.livemode flag
- Live customer portal config:
- Recreate the portal configuration in live mode (same features as sandbox)
- Document the new
bpc_* ID
Day-of-signing for first HF customer (~10 min)
When Andrew signs the engagement letter:
- Create live customer:
python
POST /v1/customers
email = <Andrew's billing email>
name = "Hundredfold Management Services" (or "Hundredfold Consulting LLC" — check engagement letter §1)
metadata[client] = "hundredfold"
metadata[engagement] = "erc-appeals"
- Issue Initial Partial Month Floor invoice (one-off, separate from subscription):
```python
# Calculate per Section 3.1(c) of engagement letter:
days_in_month =
billable_days = days_in_month - signing_day_of_month
daily_rate = (9900 * 0.5) / days_in_month # cents: int(990000 * 0.5 / days_in_month)
total_cents = round(daily_rate * billable_days * 100) # if working in dollars; or just int math in cents
POST /v1/invoiceitems
customer =
amount =
currency = usd
description = "HF Appeals — Initial Partial Month Floor (ramp-up, 50% rate × {billable_days} days)"
POST /v1/invoices
customer =
collection_method = send_invoice
days_until_due = 10
auto_advance = true # Stripe will finalize on next cycle
# Or finalize manually + email immediately:
POST /v1/invoices//finalize
POST /v1/invoices//send
3. **Create subscription starting first day of next full calendar month**:python
POST /v1/subscriptions
customer =
items[0][price] =
items[1][price] =
billing_cycle_anchor =
proration_behavior = none # we already handled the partial month manually
collection_method = send_invoice
days_until_due = 10
metadata[client] = "hundredfold"
metadata[engagement] = "erc-appeals"
```
Operational hooks
- ERCie calls
stripe_meter.report_completed_appeal(customer_id, count=1, appeal_id=<HubSpot deal id>) when an appeal passes the human approval gate.
- Webhook events post to #hf-dashboard via the deployed Pages function.
- Customer Portal session URLs can be generated on demand for Andrew via
POST /v1/billing_portal/sessions (drop the URL in #ryan-workbench when needed).
Known trade-offs
- Net-10 subscription-wide. Engagement letter §3.4 specifies Net-10 for floor and Net-30 for overage; Stripe's
days_until_due is per-subscription, not per-item. We accept Net-10 for both. (Andrew gets billed slightly faster than the contract guarantees on overage; he won't complain.)
- HubSpot Private App scope. Per-pipeline scoping enforced application-side, not natively. Engagement letter §7(a) [VERIFY] flag exists for lawyer review.
Sandbox cleanup post-cutover
Once live mode is operational and validated:
- Sandbox products + prices remain (no charge to keep)
- Test webhook endpoint can be deleted (
we_1TSqIqPo7Ey3D4jvPnTkmJVa)
- Test customer + subscription can be canceled (no real money was ever at stake)