| name | stripe-standard |
| description | Scaffolds a Stripe **Standard account** integration (no Connect) in Supabase + React/Flutter projects. Generates US-STRIPE-CHECKOUT with up to 12 UCs covering the 4 canonical billing modalities (single subscription, tiered subscriptions, metered billing, one-shot checkout) in the project's spec backend, backend Edge Functions + SQL migrations with RLS, frontend templates with Payment Element/Sheet + Apple/Google Pay + Express Checkout, Stitch designs (if VEG configured), reuses the stripe-safety-guard hook, events catalog, and wires the official Stripe MCP. Use when the user says "stripe standard", "stripe sin connect", "subscriptions saas", "checkout one-shot", "billing saas", "monta pagos saas", "monta pagos e-commerce". v1 scope: Supabase only, the 4 modalities are flags so the user opts in.
|
| context | direct |
| allowed-tools | Read, Grep, Glob, Bash(*), Write, Edit, mcp__specbox-engine__*, mcp__stitch__* |
/stripe-standard — Stripe billing scaffolder for normal (non-Connect) accounts
The companion of /stripe-connect for the 80% of Stripe consumers that don't
need a marketplace: SaaS subscriptions, e-commerce one-shot, B2B invoicing,
metered billing, donations, paywalls. Generates the same kind of bundle
(spec + Edge Functions + SQL + RLS + frontend templates + Stitch designs +
safety hook) but tuned for a single Stripe account with a single
webhook endpoint and zero Connect machinery.
When to use this vs /stripe-connect
| Use case | Skill |
|---|
| You sell access to your own product (SaaS, app, content) | /stripe-standard |
| You run an e-commerce shop selling your own goods | /stripe-standard |
| You have one-shot purchases (donations, lifetime deals) | /stripe-standard |
| You need metered billing (usage-based pricing) | /stripe-standard |
| You operate a marketplace where other sellers receive money | /stripe-connect |
| You take a cut from third-party transactions | /stripe-connect |
If unsure, default to /stripe-standard. Adding Connect later is a refactor
but supported by the same setup_webhook_endpoints(account_mode='connect')
of the underlying MCP — no data loss.
Uso
/stripe-standard
Sin argumentos por defecto activa las 4 modalidades. Para acotar:
/stripe-standard --modes=single_sub,one_shot
/stripe-standard --modes=metered
Modalidades válidas:
| Flag | Qué genera |
|---|
single_sub | 1 sola suscripción mensual o anual fija (caso SaaS clásico) |
tiered_sub | Múltiples planes con upgrade/downgrade y proration |
metered | Facturación por uso (usage records + reporting) |
one_shot | Pagos únicos sin recurrencia (e-commerce, donaciones, lifetime) |
Alcance v1 (opinionado)
| Dimensión | Decisión |
|---|
| Backend | Supabase únicamente (Neon/Firestore/FastAPI → v2) |
| Frontend | React 19 o Flutter 3.38+ |
| Account type | Stripe Standard (la cuenta normal — sin Connect) |
| Charge model | Direct charges sobre la propia cuenta |
| Subscriptions | 4 modalidades disponibles, opt-in vía flags |
| Checkout UX | Embedded-only: Payment Element (React) + Payment Sheet (Flutter). Hosted Checkout queda como fallback opcional vía stripe-create-checkout-session |
| Apple/Google Pay | Default on |
| Customer Portal | Sí (en Standard sí podemos abrir el portal — el customer vive en nuestra propia cuenta) |
| Webhook endpoints | 1 solo (vs 2 de Connect) |
| MCP underneath | specbox-stripe-mcp v0.2 con account_mode='standard' |
Paso 0 — Preflight: detectar entorno del proyecto
0.1 Validar que estamos en un proyecto SpecBox onboardeado
test -f .claude/settings.local.json || test -f .claude/settings.json || {
echo "ERROR: Este directorio no parece un proyecto SpecBox. Ejecuta 'onboard_project' primero."
exit 1
}
0.2 Detectar stack frontend
if [ -f package.json ] && grep -q '"react"' package.json; then STACK="react"; fi
if [ -f pubspec.yaml ] && grep -q "flutter:" pubspec.yaml; then
if [ -d ios ] || [ -d android ]; then STACK="flutter-mobile"; else STACK="flutter-web"; fi
fi
Si no detecta ni React ni Flutter → abortar: "v1 solo soporta React o Flutter. Otros stacks no están cubiertos."
0.3 Detectar backend Supabase (obligatorio en v1)
test -d supabase && test -f supabase/config.toml || {
echo "ERROR: v1 de /stripe-standard requiere Supabase CLI inicializado."
echo "Ejecuta 'supabase init' antes de continuar, o espera a v2 para otros backends."
exit 0
}
0.4 Detectar spec backend activo (Trello / Plane / FreeForm)
Leer .claude/settings.local.json:
trello.boardId → Trello
plane.defaultProject → Plane
- Sin ninguno → FreeForm en
doc/tracking/
0.5 Detectar presencia de VEG
test -d doc/veg && test -f doc/design/brand-kit.md && VEG_PRESENT=true || VEG_PRESENT=false
0.6 Parsear flag --modes
MODES_INPUT="${1:---modes=single_sub,tiered_sub,metered,one_shot}"
MODES=$(echo "$MODES_INPUT" | sed 's/--modes=//')
VALID="single_sub tiered_sub metered one_shot"
for m in $(echo "$MODES" | tr ',' ' '); do
echo "$VALID" | grep -qw "$m" || {
echo "ERROR: modalidad '$m' no soportada. Válidas: single_sub, tiered_sub, metered, one_shot."
exit 1
}
done
0.7 Detectar specbox-stripe-mcp instalado
test -d packages/specbox-stripe-mcp || command -v specbox-stripe-mcp >/dev/null || {
echo "WARN: specbox-stripe-mcp no detectado. La skill puede continuar pero los tools de"
echo " setup-as-code (verify_account_setup, setup_webhook_endpoints, etc.) no estarán"
echo " disponibles para el proyecto. Instálalo con: pip install specbox-stripe-mcp"
}
Paso 1 — Confirmar plan con el usuario
Antes de tocar el filesystem, presentar:
📋 Stripe Standard scaffolder — plan de generación
Stack detectado: {STACK}
Spec backend: {Trello|Plane|FreeForm}
VEG presente: {sí|no}
Modalidades: {modes activadas}
Va a crear:
- 1 US-STRIPE-CHECKOUT + N UCs en {spec_backend}
- Edge Functions Supabase ({lista funciones})
- Migraciones SQL ({lista migraciones})
- Templates frontend en {src/billing|lib/billing}/
- {N} pantallas Stitch (si VEG activo)
- 1 PRD en doc/prd/stripe_standard_prd.md
Va a NO crear:
- Cuenta Stripe (debes tenerla ya, en test mode)
- Secrets en .env (los pegas tú; la skill solo guía con el placeholder)
¿Continuar? (s/n)
Si responde n → exit 0 sin tocar nada.
Paso 2 — Crear US-STRIPE-CHECKOUT + UCs en spec backend (AC-01..AC-06)
El catálogo canónico de los 12 UCs vive en templates/uc-catalog.json. La skill
filtra por MODES activadas y llama import_spec con el subset.
catalog = json.load(open(".claude/skills/stripe-standard/templates/uc-catalog.json"))
selected_ucs = [
uc for uc in catalog["ucs"]
if any(m in uc["modes"] for m in MODES.split(","))
or "always" in uc["modes"]
]
spec = {
"user_stories": [{
"us_id": "US-STRIPE-CHECKOUT",
"name": "Integración de pagos Stripe (cuenta Standard, modalidades activadas: " + MODES + ")",
"description": "...",
"hours": sum(u["hours"] for u in selected_ucs),
"use_cases": selected_ucs,
}]
}
import_spec(board_id=board_id, spec=spec)
2.1 Re-run idempotente (AC-05)
Si list_us(board_id) ya devuelve un US-STRIPE-CHECKOUT:
⚠ Ya existe US-STRIPE-CHECKOUT en este board.
¿Qué quieres hacer?
(1) skip — no cambiar nada en el spec backend
(2) update — añadir las UCs nuevas (las modalidades que faltan)
(3) replace — borrar la US existente y crearla desde cero (destructivo)
Por defecto la skill elige (1) si no hay TTY interactivo.
2.2 Fallback si el spec backend está offline
Try/catch sobre import_spec. Si falla:
⚠ Spec backend {Trello|Plane} no responde. Guardando como FreeForm local en doc/tracking/.
Llamar set_auth_token(backend_type="freeform", root_path="doc/tracking") y reintentar.
Paso 3 — Generar PRD adjunto (AC-07)
Escribir doc/prd/stripe_standard_prd.md desde
templates/docs/stripe_standard_prd.md.template con las secciones por modalidad
activada. Cada modalidad incluye:
- Caso de uso (resumen de 2-3 frases)
- Flujo principal (numerado)
- Casos de error (lista)
- Eventos Stripe relevantes (subset del events catalog)
- Frontend components afectados
Si --modes=single_sub,one_shot, el PRD solo tiene esas 2 secciones.
Paso 4 — Escribir templates backend Supabase (AC-07/UC-007)
Copiar y parametrizar desde .claude/skills/stripe-standard/templates/supabase/:
4.1 Edge Functions
Funciones generadas según modalidades activadas:
| Function | Modalidad |
|---|
stripe-create-customer/index.ts | always |
stripe-webhook/index.ts | always (1 solo endpoint, sin separar platform/connect) |
stripe-create-subscription/index.ts | si activas single_sub, tiered_sub o metered |
stripe-create-payment-intent/index.ts | si activas one_shot |
stripe-create-checkout-session/index.ts | siempre — fallback hosted (con ui_mode='embedded' por defecto) |
stripe-create-portal-session/index.ts | always (Customer Portal) |
stripe-report-usage/index.ts | si activas metered |
Placeholders: {project_name}, {frontend_url}, {currency} (default eur).
4.2 Migraciones SQL
3 migraciones copiadas a supabase/migrations/ con timestamp prefix:
| Migration | Contenido |
|---|
NNN_stripe_customers.sql | tabla stripe_customers (user_id FK auth.users, stripe_customer_id UNIQUE) |
NNN_stripe_subscriptions.sql | tabla stripe_subscriptions (customer_id FK, stripe_subscription_id, price_id, status, current_period_end, cancel_at_period_end, metadata JSONB) |
NNN_stripe_processed_events.sql | tabla stripe_processed_events (event_id UNIQUE PK, type, processed_at) |
RLS policies en una 4ª migración: usuarios solo ven sus propias rows; service_role
lee/escribe todo desde Edge Functions.
Todas con CREATE ... IF NOT EXISTS para idempotencia.
Paso 5 — Escribir templates frontend (UC-009 / UC-010)
5.1 React (STACK=react)
Copiar desde templates/react/ a src/billing/ del proyecto:
stripe-provider.tsx — <Elements> con appearance parametrizada por brand-kit
subscription-form.tsx — <PaymentElement> + <ExpressCheckoutElement> para single/tiered subs
checkout-embedded.tsx — loadStripe + initEmbeddedCheckout para one-shot
paywall-gate.tsx — wrapper que bloquea acceso si no hay sub activa
billing-portal-link.tsx — botón que abre el Customer Portal vía Edge Function
usage-meter.tsx — solo si metered activado (componente para mostrar uso)
use-billing.ts — hook centralizado de estado de subs/payments
Mergear dependencias en package.json:
{
"@stripe/stripe-js": "^3",
"@stripe/react-stripe-js": "^2"
}
5.2 Flutter (STACK=flutter-mobile o flutter-web)
Copiar desde templates/flutter/ a lib/billing/:
stripe_service.dart — init + Apple Pay + Google Pay
subscription_screen.dart — PaymentSheet para single/tiered subs
one_shot_checkout_sheet.dart — PaymentSheet para compras únicas
paywall_gate.dart — widget gate que bloquea si no hay sub
billing_portal_button.dart — abre el portal en navegador (url_launcher)
usage_meter_card.dart — solo si metered activado
billing_controller.dart — estado centralizado
Mergear dependencias en pubspec.yaml:
flutter_stripe: ^11.0.0
url_launcher: ^6.0.0
Paso 6 — Stitch designs (UC-011)
Si VEG_PRESENT=true, generar pantallas vía mcp__stitch__generate_screen_from_text.
Pantallas según modalidades activadas:
| Pantalla | Modalidades requeridas |
|---|
paywall.html | siempre |
billing-portal.html | siempre |
checkout-success.html | siempre |
checkout-cancel.html | siempre |
subscription-management.html | si hay alguna sub modalidad activa |
metered-usage-dashboard.html | si metered activado |
Guardar en doc/design/stripe_standard/. Registrar prompts en
doc/design/stripe_standard/stripe_standard_stitch_prompts.md.
Si VEG_PRESENT=false → saltar este paso silenciosamente.
Paso 7 — Reusar hook stripe-safety-guard (UC-012)
El hook ya existe en .claude/hooks/stripe-safety-guard.mjs (vino con
/stripe-connect). Detecta los 5 anti-patterns en src/billing/,
lib/billing/ y supabase/functions/stripe-*:
sk_live_* hardcoded
- Webhook handler sin verificación de firma
- Webhook handler sin idempotencia (
stripe_processed_events)
redirectToCheckout o ui_mode='hosted'
- Payment Links
No tocamos el hook. Solo verificamos que está activado en .claude/settings.json:
grep -q "stripe-safety-guard" .claude/settings.json || {
echo "WARN: stripe-safety-guard hook no activo. Activa con /compliance --fix."
}
Paso 8 — Wire Stripe MCP oficial (idéntico a /stripe-connect Paso 8)
Mergear en .claude/settings.local.json:
{
"mcpServers": {
"stripe": {
"command": "npx",
"args": ["-y", "@stripe/mcp", "--api-key", "${STRIPE_API_KEY}"],
"env": { "STRIPE_API_KEY": "${STRIPE_SECRET_KEY}" }
}
}
}
Esto da acceso al MCP oficial de Stripe (runtime de negocio: customers,
charges, refunds, etc.) además del specbox-stripe-mcp (setup-as-code).
Paso 9 — Inyectar secrets en Supabase Edge Functions (UC-013)
Standard solo necesita 3 secrets (vs los 4 de Connect):
| Secret | Origen |
|---|
STRIPE_SECRET_KEY | tu cuenta Stripe (test mode) |
STRIPE_WEBHOOK_SECRET | salida de stripe listen --forward-to ... o el dashboard |
STRIPE_PUBLISHABLE_KEY | tu cuenta Stripe |
NO existe STRIPE_WEBHOOK_SECRET_CONNECT aquí — Standard solo tiene 1 endpoint.
9.1 Detectar specbox-supabase MCP
Intentar mcp__specbox-supabase__list_edge_secrets_tool({supabase_pat: "...", project_ref: "..."}).
- Si responde → Paso 9.2 (auto-inyección).
- Si no responde / no está registrado → Paso 9.3 (manual, escribe doc/PENDING_SECRETS.md).
9.2 Inyección automática
mcp__specbox-supabase__set_edge_secret_tool({
supabase_pat: env.SUPABASE_PAT,
project_ref: env.SUPABASE_PROJECT_REF,
secrets: {
STRIPE_SECRET_KEY: env.STRIPE_SECRET_KEY,
STRIPE_WEBHOOK_SECRET: env.STRIPE_WEBHOOK_SECRET,
STRIPE_PUBLISHABLE_KEY: env.STRIPE_PUBLISHABLE_KEY,
},
confirm: true,
reason: "/stripe-standard initial setup"
})
Verificar con list_edge_secrets({expected_names: [...]}).
9.3 Fallback manual
Si MCP ausente, escribir doc/PENDING_SECRETS.md:
# Secrets pendientes
specbox-supabase MCP no detectado. Copia estos 3 secrets manualmente en:
https://supabase.com/dashboard/project/{project_ref}/settings/functions
STRIPE_SECRET_KEY = <from .env>
STRIPE_WEBHOOK_SECRET = <from `stripe listen` output>
STRIPE_PUBLISHABLE_KEY = <from .env>
Engram observation: registrar éxito/fallo del paso sin valores de secrets.
Paso 10 — Tests + acceptance evidence (UC-015)
Generar tests/acceptance/ con un test por modalidad activada:
| Test | Modalidad |
|---|
subscribe_single_sub.spec.ts (React) o _test.dart (Flutter) | single_sub |
switch_tier.spec.ts | tiered_sub |
metered_billing.spec.ts | metered |
one_shot_checkout.spec.ts | one_shot |
Cada test cubre el happy path + 1-2 error paths (decline, 3DS challenge).
Paso 11 — Próximos pasos (mostrar al usuario)
✓ /stripe-standard completado en {duration}.
Siguientes pasos manuales:
1. {Si Paso 9 fue manual} Copiar los 3 secrets en Supabase dashboard.
2. Ejecutar `supabase db push` para aplicar las migraciones.
3. Ejecutar `stripe listen --forward-to <tu-edge-url>/stripe-webhook` en
terminal separado para testing local.
4. (Opcional, no bloqueante) Activar Stripe Tax si vas a vender en EU.
5. /implement US-STRIPE-CHECKOUT — ejecutará los UCs en orden.
📋 Catálogo de eventos relevantes en doc/stripe-standard-events.md.
Anexo A — Comparativa Standard vs Connect
| Dimensión | Standard | Connect |
|---|
| Webhook endpoints | 1 (platform-scope) | 2 (platform + connect) |
| Tablas SQL | 3 (customers, subs, events) | 4 (riders/sponsorships también) |
| Edge Functions | 5-7 según modos | 5 fijas |
| Customer Portal | sí (built-in) | requiere onboarding del seller |
application_fee_percent | N/A | dinámico por seller |
| Activación dashboard | nada | hay que activar Connect explícitamente |
Errores frecuentes (FAQ rápido)
Q: Mi proyecto ya tiene /stripe-connect. ¿Puedo añadir /stripe-standard?
A: Técnicamente sí pero no recomendado. El cliente Stripe abstracto no
distingue Standard de Connect en runtime. Si ya tienes Connect Express, los
flujos de Standard van por la cuenta plataforma — funciona pero crea confusión.
Mejor escoge una de las dos modalidades.
Q: ¿Puedo migrar de /stripe-connect a /stripe-standard?
A: La parte de spec/templates es regenerar la skill. La parte de Stripe es
otra cosa: si ya cobraste con Direct charges en Connect, no se mueve a la
plataforma. Customers + subscriptions seguirán viviendo en las cuentas
conectadas. Es una migración pesada — pregunta antes de intentarla.
Q: metered vs tiered_sub, ¿cuál escojo?
A: tiered_sub = N planes con precio fijo, el usuario puede subir/bajar.
metered = un plan + se factura por uso (ej: $0.001 por API call). Son
ortogonales: puedes activar las dos.
Referencias
- Plan original:
doc/plans/stripe_standard_plan.md (auto-generado por /plan US-STRIPE-STANDARD)
- MCP underlying:
packages/specbox-stripe-mcp/ v0.2 (account_mode='standard')
- Skill hermana:
/stripe-connect
- Tracking: SpecBox board
ff-bc73b5d69f91, US-STRIPE-STANDARD