Stripe Test Mode Wiring Verification
Date: 2026-05-13 UTC Author: sre-agent Scope: Staging environment — TEST MODE ONLY T-minus: 10 days to v1 launch (2026-05-23 UTC) Related issues: #2020, #2021, #1682 (pre-launch-blocker)
Executive summary
The Stripe test-mode integration is NOT ready for end-to-end smoke testing on staging. Phase 1 (configuration verification) failed on every check. Phase 2 (smoke test) and Phase 3 inventory are blocked by Phase 1 gaps. Three structural gaps exist: (1) Stripe test keys are absent from vault staging environment and both staging Heroku apps, (2) Queue staging has no deployed application slug and an empty database, (3) the webhook handler (#1682) is not yet shipped. This is consistent with the pre-launch punch list (#2003) which marks Stripe billing as AT RISK / HIGH.
The billing path is a pre-launch-blocker. At current velocity (webhook handler unstarted, Queue staging undeployed, schema not applied), a full staging soak requires 4–6 dev-days plus ops setup time before the 2026-05-23 UTC deadline.
Phase 1 — Configuration verification
1.1 Vault paths — FAIL
Live vault audit run at 2026-05-13 20:06 UTC via scripts/vault/audit_coverage.py.
Stripe keys are present in the dev vault environment under /MooseQuest/stripe/. They are absent from the staging vault environment entirely. No /MooseQuest/stripe/ secrets exist in staging.
| Secret | prod | staging | dev | First 12 chars (dev) |
|---|---|---|---|---|
STRIPE_SECRET_KEY |
missing | missing | present | sk_test_51TV... |
STRIPE_PUBLISHABLE_KEY |
missing | missing | present | pk_test_51TV... |
STRIPE_WEBHOOK_SECRET |
missing | missing | present | whsec_3cHDOO... |
STRIPE_RAXX_DEV_BOT_KEY |
missing | missing | present | rk_test_51TV... |
Key mode confirmation: all dev keys have sk_test_, pk_test_, rk_test_, and whsec_ prefixes. TEST MODE confirmed. No live keys found anywhere in vault.
Note: the architecture doc (stripe-customer-billing.md §7.6) names the var STRIPE_RESTRICTED_KEY, but the vault stores it as STRIPE_SECRET_KEY. Operator action required to confirm which name Queue/Raptor application code reads before setting Heroku config vars.
Vault path for the Raptor billing design: docs/architecture/stripe-customer-billing.md §7.6 specifies /Raxx/Raptor/Billing/Stripe/ for v1. This path does not exist in any vault environment. The keys at /MooseQuest/stripe/ are the actual location. These paths need reconciliation before the live transition.
1.2 Heroku config var wiring — FAIL
heroku config -a raxx-api-staging | grep -i stripe — no output (zero Stripe vars set).
heroku config -a raxx-queue-staging — only DATABASE_URL is set. Zero other config vars.
Neither STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PUBLISHABLE_KEY, nor any Stripe-adjacent var is present on either staging Heroku app.
1.3 Webhook endpoint reachable — FAIL
Queue staging (raxx-queue-staging) has no deployed application slug. The app was provisioned on 2026-05-11 (Heroku release v4) but no container image has been built or released. Probe result:
curl https://raxx-queue-staging-403c1aa5941f.herokuapp.com/health
→ Heroku default "Welcome to your new app!" HTML (no queue-server running)
Raptor staging (raxx-api-staging) is running (health check returns {"status":"ok"}). However, Raptor does not have a Stripe webhook receiver — the webhook handler (POST /api/billing/webhook) is scoped to Queue per the v3 architectural decision (ADR-0071, ADR-0075). The existing Raptor billing routes (/api/billing/summary) are for the operator-facing vendor spend dashboard, not the customer Stripe webhook path.
Raptor staging probes returned {"error":"direct_origin_blocked"} — CF Access origin-guard is active, which is correct. These are not the target webhook endpoints.
1.4 Webhook secret match — CANNOT VERIFY
Stripe dashboard verification is not possible without a running webhook endpoint registered in Stripe. Since 1.3 failed (no running Queue staging instance, no registered webhook URL), this check is blocked.
Phase 2 — End-to-end smoke test
Status: BLOCKED
All Phase 2 scenarios are blocked by Phase 1 failures. Specific blockers:
| Scenario | Blocker |
|---|---|
| Customer creation | No Stripe API key on raxx-queue-staging |
| Subscription creation | No deployed Queue staging instance |
Successful payment (4242...) |
Webhook handler not implemented (#1682 OPEN) |
Failed payment (4000...0002) |
Same |
| Subscription cancellation | Same |
| Customer Portal session | No CRUD endpoints wired to Stripe API |
No test data was created in Stripe dashboard. No cleanup required.
Phase 3 — Gap inventory
| Component | Status | Notes |
|---|---|---|
| Stripe Customer creation on signup | MISSING | customer_service.cpp exists in Queue but Queue staging is not deployed; no signup flow wired to it |
| Subscription price IDs in code | MISSING | No price IDs found in code or config; Stripe Products/Prices not referenced in any source file |
Webhook handler — customer.created |
MISSING | #1682 OPEN / blocked / pre-launch-blocker; webhook_processor.h referenced in tests but not implemented |
Webhook handler — customer.subscription.created |
MISSING | Same |
Webhook handler — customer.subscription.updated |
MISSING | Same |
Webhook handler — customer.subscription.deleted |
MISSING | Same |
Webhook handler — invoice.payment_succeeded |
MISSING | Same |
Webhook handler — invoice.payment_failed |
MISSING | Same |
Webhook handler — invoice.upcoming |
MISSING | Same |
HMAC validation (Stripe-Signature) |
MISSING | hmac_util.h referenced in test_hmac_util.cpp but file does not exist in queue/src/stripe/ |
Idempotency / dedup (processed_stripe_events) |
MISSING | Table migration exists in sqitch plan but not applied to staging DB |
| Customer Portal session endpoint | MISSING | No /billing/portal route in any handler |
| Dunning / Smart Retries config | MISSING | No Stripe Smart Retries config; no dunning state handling |
| Cancellation flow | MISSING | subscription_service.cpp has cancel method but end-to-end flow not wired |
| Plan change / upgrade-downgrade | MISSING | feature_locked_at column in schema; downgrade detection in test stubs only |
| Stripe Tax | MISSING | No reference to Stripe Tax in any config or code |
| Audit event emission per webhook | MISSING | billing_action_log table in schema; no emission code in webhook handler |
| Customer-facing billing UI | MISSING | No billing dashboard in Antlers (frontend/trademaster_ui) |
| Admin-facing customer billing view in console | PARTIAL | #408 / #409 Console billing views depend on Queue billing API; Queue not deployed |
| Queue billing DB schema applied (staging) | MISSING | Queue staging DB is empty — \dt returns no tables |
| Queue staging deployed | MISSING | No slug released; v4 = only DB provisioning |
| Stripe test keys in vault staging | MISSING | Keys in dev env only; staging path empty |
| Stripe test keys in Heroku staging apps | MISSING | Zero STRIPE_* vars on raxx-api-staging or raxx-queue-staging |
FLAG_QUEUE_BILLING enabled on staging |
MISSING | Flag default=false; not set on raxx-queue-staging |
FLAG_QUEUE_STRIPE_SERVICE enabled on staging |
MISSING | Flag default=false; not set on raxx-queue-staging |
| Billing migration chain in Raptor (v1 stopgap) | MISSING | billing_subscription, billing_invoice, processed_stripe_events not in any Raptor migration; only billing_customers and billing_action_log exist in 024_billing_dsr_schema.sql |
What IS shipped (Queue service layer)
| Component | Status | Notes |
|---|---|---|
StripeClient C++ (libcurl wrapper) |
SHIPPED | queue/src/stripe/stripe_client.cpp — fromEnv(), post(), get(), del() |
CustomerService |
SHIPPED | queue/src/stripe/customer_service.cpp — create, get |
SubscriptionService |
SHIPPED | queue/src/stripe/subscription_service.cpp — create, get, cancel |
InvoiceService |
SHIPPED | queue/src/stripe/invoice_service.cpp |
| Billing CRUD read endpoints | SHIPPED (code) | customers_handler.cpp, subscriptions_handler.cpp, invoices_handler.cpp — routes registered at /api/v1/internal/billing/*; not reachable because app is not deployed |
| Queue billing DB schema (sqitch) | SHIPPED (code) | 6 migration files in queue/migrations/sqitch/deploy/; not applied to staging DB |
billing_customers + DSR tables in Raptor |
PARTIAL | 024_billing_dsr_schema.sql creates billing_customers and billing_dsr_request; NOT the full subscription/invoice model from the stripe-customer-billing.md design |
| Console migration 0034 (flag promotion) | SHIPPED | STRIPE_RESTRICTED_KEY prereq noted in migration comments |
Pre-launch-blocker assessment (9 days to 2026-05-23 UTC)
| Gap | Blocker? | Effort | Owner | Due |
|---|---|---|---|---|
| Stripe test keys in vault staging | YES — blocks all E2E | 30 min (operator) | operator | ASAP |
| Stripe test keys on Heroku staging apps | YES — blocks all E2E | 30 min (operator) | operator | ASAP |
| Queue staging slug deploy | YES — blocks webhook path | 2–4h (ops + CI wiring) | sre-agent + operator | ASAP |
| Queue staging DB schema apply | YES — blocks persistence | 30 min (after slug deploy) | operator | After deploy |
Webhook handler #1682 |
YES — blocks E2E smoke | 2–3 dev-days (feature-developer) | feature-developer | 2026-05-20 to soak 48h |
| Stripe Price IDs in code/config | YES — blocks subscription creation | 1 day (feature-developer) | feature-developer | 2026-05-18 |
| Raptor billing_subscription/invoice tables | YES if Raptor v1 stopgap is active | 1 day (feature-developer) | feature-developer | clarify architecture |
| Customer Portal session endpoint | Deferrable | 1–2 days | feature-developer | post-v1 |
| Stripe Tax | Deferrable (US nexus may not apply at launch) | operator decision | operator | decision needed |
| Customer-facing billing UI | YES if paid signup at launch | 3–5 days | feature-developer | Depends on paid-tier decision |
| Dunning / Smart Retries | Deferrable | Stripe config only | operator | post-v1 |
| Audit event emission | YES for compliance | 1 day (feature-developer) | feature-developer | with #1682 |
Critical path to minimal-viable billing soak
- Operator — provision Stripe test keys to vault staging + Heroku staging (issue #2020). 30 min.
- Operator — deploy Queue staging container (issue #2021 has commands). 2–4h.
- Operator — apply sqitch billing schema to Queue staging DB (issue #2021). 30 min.
- Feature-developer — implement
#1682(webhook handler + HMAC util). 2–3 days. - Operator — register staging webhook URL in Stripe dashboard, set
STRIPE_WEBHOOK_SECRETfrom Stripe dashboardwhsec_value. - Sre-agent — re-run Phase 1 + Phase 2 verification after above complete.
- 48h soak with
FLAG_QUEUE_BILLING=trueon staging before enabling on prod.
Earliest possible live-mode swap: 2026-05-21–22 UTC, assuming steps 1–4 start immediately and feature-developer begins #1682 today. This is zero-slack against the 2026-05-23 UTC launch gate.
Action items
| # | Action | Owner | Due | Issue |
|---|---|---|---|---|
| 1 | Provision Stripe test keys to vault staging + Heroku staging apps | operator | 2026-05-14 UTC | #2020 |
| 2 | Deploy Queue staging container + apply sqitch billing schema | operator + sre-agent | 2026-05-14 UTC | #2021 |
| 3 | Implement webhook handler (#1682) + HMAC util | feature-developer | 2026-05-20 UTC | #1682 |
| 4 | Add Stripe Price IDs to config/code for all plan tiers | feature-developer | 2026-05-18 UTC | TBD |
| 5 | Decide: Raptor v1 billing tables or Queue-only for launch | operator | 2026-05-14 UTC | ADR-0073/0075 |
| 6 | Register staging webhook URL in Stripe dashboard after Queue deploy | operator | 2026-05-15 UTC | — |
| 7 | Re-run Phase 1 + Phase 2 E2E smoke test after #1682 ships | sre-agent | 2026-05-21 UTC | — |
| 8 | Reconcile vault path discrepancy (/MooseQuest/stripe/ vs /Raxx/Raptor/Billing/Stripe/) before live transition |
operator | 2026-05-22 UTC | — |
Vault path discrepancy (escalation note)
The architecture doc (stripe-customer-billing.md §7.6) specifies secrets should live at:
- /Raxx/Raptor/Billing/Stripe/STRIPE_RESTRICTED_KEY (v1)
- /Raxx/Queue/Billing/Stripe/STRIPE_RESTRICTED_KEY (post-migration)
The actual vault path is /MooseQuest/stripe/STRIPE_SECRET_KEY. The var name also differs (STRIPE_RESTRICTED_KEY vs STRIPE_SECRET_KEY). Before the live-mode transition, the operator must confirm:
1. Which path does the running application code actually read from?
2. Which var name does the code read (STRIPE_RESTRICTED_KEY or STRIPE_SECRET_KEY)?
3. The restricted key (rk_test_...) is separate from the secret key (sk_test_...) — which one gates Raptor vs Queue?
This is a misconfiguration risk, not a live-key exposure. Documenting here for resolution before live transition.
References
- Architecture:
docs/architecture/stripe-customer-billing.md - Issues: #1682 (webhook handler — OPEN/blocked), #2020 (vault/Heroku config), #2021 (Queue staging deploy + schema)
- Pre-launch punch list: #2003
- Vault snapshot:
docs/ops/2026-05-12-vault-coverage-snapshot.md - ADR-0071, ADR-0073, ADR-0075 (billing architecture decisions)