Raxx · internal docs

internal · gated

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.cppfromEnv(), 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

  1. Operator — provision Stripe test keys to vault staging + Heroku staging (issue #2020). 30 min.
  2. Operator — deploy Queue staging container (issue #2021 has commands). 2–4h.
  3. Operator — apply sqitch billing schema to Queue staging DB (issue #2021). 30 min.
  4. Feature-developer — implement #1682 (webhook handler + HMAC util). 2–3 days.
  5. Operator — register staging webhook URL in Stripe dashboard, set STRIPE_WEBHOOK_SECRET from Stripe dashboard whsec_ value.
  6. Sre-agent — re-run Phase 1 + Phase 2 verification after above complete.
  7. 48h soak with FLAG_QUEUE_BILLING=true on 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