/stripe-switch-account — Stripe credentials rotation skill
Companion of /stripe-connect and /stripe-standard. Where those scaffold a
brand-new integration, this one rotates an already-deployed integration to a
different Stripe account. Common cases:
- Test → live (going to production for the first time)
- Live → live (changing legal entity, splitting from a former partner)
- Live → test (rolling back to a sandbox after an incident)
The skill never moves money, customers or subscriptions across accounts —
those are immutable once created. What it rotates is the infrastructure:
which account the platform's Edge Functions talk to, where the webhooks
fire, which sk_* lives in Supabase secrets.
Uso
/stripe-switch-account
Sin argumentos. La skill detecta el alias store, pregunta from/to, propone un plan, pide confirmación literal y ejecuta.
Pre-requisitos
- Alias store con al menos 2 entradas. Crear con:
La store vive cifrada enmcp__specbox-stripe__store_stripe_alias_tool({ alias_name: "prod", stripe_api_key: "sk_live_...", project_path: "/abs/path/to/project" }).claude/secrets/stripe_aliases.enc.json. - specbox-stripe-mcp v0.3+ registrado en
.claude/settings.local.json. - (Recomendado)
specbox-supabase-mcpregistrado para auto-rotación de Edge Function secrets. Si falta, la skill generadoc/PENDING_SWITCH_SECRETS.mdy guía al usuario para hacerlo manualmente.
Paso 0 — Preflight
0.1 Validar proyecto SpecBox
test -f .claude/settings.local.json || test -f .claude/settings.json || {
echo "ERROR: No es un proyecto SpecBox. Ejecuta onboard_project primero."
exit 1
}
0.2 Detectar specbox-stripe-mcp
Comprobar que el MCP está registrado: grep -q specbox-stripe .claude/settings.local.json.
Si falta → abortar con instrucciones de instalación:
ERROR: specbox-stripe-mcp no está registrado en este proyecto.
Añádelo a .claude/settings.local.json bajo "mcpServers".
Mínimo requerido: v0.3.0 (incluye switch_stripe_account).
0.3 Detectar el modo del proyecto
Leer package.json / pubspec.yaml / Edge Functions existentes:
- ¿Hay
supabase/functions/stripe-webhookcon un solo endpoint? →account_mode='standard'. - ¿Hay 2 webhooks (platform + connect) o referencias a
application_fee_percent? →account_mode='connect'.
Si la heurística es ambigua, preguntar al usuario.
0.4 Listar aliases disponibles
mcp__specbox-stripe__list_stripe_aliases_tool_mcp({ project_path: "{abs}" })
Si hay menos de 2 → abortar:
ERROR: Necesitas al menos 2 aliases (origen + destino).
Tienes registrados: [lista]
Crea otro con store_stripe_alias_tool antes de switch.
Paso 1 — UX inicial
Mostrar al usuario:
🔄 Stripe Switch Account
Aliases registrados en este proyecto:
• prod (live, last used 2026-04-29 14:22)
• staging (test, last used 2026-04-15 10:01)
• legacy (live, never used)
¿De qué alias migras? (from): prod
¿A qué alias migras? (to): staging
¿Modo de cuenta? standard
¿Qué hacer con la cuenta de origen tras el switch?
(1) keep_old_active — no tocar nada (DEFAULT, recomendado para rollback rápido)
(2) archive_products_only — archivar los products SpecBox, dejar webhooks
(3) deactivate_webhooks_only — deshabilitar webhooks, dejar products
(4) full_archive — todo lo anterior + cancelar subs SpecBox-managed (irreversible)
Elección: 1
Validar before continuar:
from != tofromytoexisten en alias_store- En
connect→ preguntar tambiénconnect_events/connect_urlsi difieren
Paso 2 — Dry-run obligatorio
mcp__specbox-stripe__switch_stripe_account_tool({
from_alias: "prod",
to_alias: "staging",
account_mode: "standard",
project_path: "{abs}",
platform_url: "https://{ref}.supabase.co/functions/v1/stripe-webhook",
platform_events: [...read from project's events.yaml or defaults...],
scope_action: "keep_old_active",
dry_run: true
})
Formatear la respuesta como Markdown:
📋 Plan de migración (dry-run)
ORIGEN (prod, sk_live_***)
Webhook endpoints: 1 SpecBox-managed
Products: 3
Subscriptions activas: 27
Customers: 142
DESTINO (staging, sk_test_***)
Webhook endpoints: 0
Products: 0
ACCIONES PROPUESTAS
1. Crear 1 webhook endpoint en destino (events: ...)
2. Replicar catálogo (3 products + sus prices) ← solo si pasaste catalog
3. Inyectar secrets en Supabase (3 keys) ← si specbox-supabase MCP detectado
↳ si no: doc/PENDING_SWITCH_SECRETS.md
4. scope_action sobre origen: keep_old_active (no toca nada)
Duración estimada: ~12 segundos
⚠️ IMPORTANTE: Las subscripciones, customers, y métodos de pago de la
cuenta origen NO se mueven. Siguen vivos en prod. Si alguien tenía
sesión iniciada y va a renovar, el cobro irá a prod, NO a staging.
Este flow es para infrastructure rotation, no migración de business data.
Paso 3 — Confirmación literal
Para ejecutar este switch, escribe EXACTAMENTE:
Yes, switch from prod to staging
(con esos espacios y mayúsculas; un fallo de typing aborta el switch)
Si el usuario escribe cualquier otra cosa → abortar sin tocar nada.
Si scope_action='full_archive' → segunda confirmación con
confirm_token="I understand this archives all SpecBox resources in the source account".
Paso 4 — Ejecutar real
mcp__specbox-stripe__switch_stripe_account_tool({
...mismo payload que dry-run...
dry_run: false
})
Streaming progress al usuario:
✓ Pre-flight OK
✓ Webhook endpoint creado en destino: we_1TabcXyz
✓ 3/3 products replicados en destino
✓ Secrets inyectados en Supabase (3 nombres: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PUBLISHABLE_KEY)
✓ scope_action keep_old_active: cuenta origen intacta
✅ Switch completado en 11.2s.
Si algún paso falla:
✗ Webhook endpoint creado en destino
✗ Products replicación: FAILED (E_LIMIT_REACHED)
🔄 Iniciando rollback automático...
✓ Webhook destino eliminado
⚠ Rollback completo. Sistema de vuelta al estado pre-switch.
Revisa los logs y vuelve a intentar.
Si rollback también falla:
🚨 Rollback parcialmente fallido. Estado del sistema mixto.
Runbook generado en: doc/SWITCH_FAILURE_RUNBOOK.md
Sigue las instrucciones manualmente.
Paso 5 — Smoke-test post-switch
Sugerir al usuario:
Próximos pasos:
1. Reload de Edge Functions (Supabase los recoge automáticamente).
2. stripe listen --forward-to {platform_url} (con la NUEVA cuenta)
3. Test de un signup nuevo:
- Card 4242 4242 4242 4242
- Verifica que aparece en https://dashboard.stripe.com/{test|live}/customers de la cuenta DESTINO.
4. Si todo OK y scope_action era 'keep_old_active' → considera ejecutar
/stripe-switch-account de nuevo con scope_action='archive_products_only'
una vez confirmes que no necesitas rollback.
Si el usuario responde "rollback please":
/stripe-switch-account
from: staging
to: prod
Es exactamente el mismo flow al revés (siempre que prod aún esté keep_old_active).
Anexo A — Errores comunes
| Error | Causa | Fix |
|---|---|---|
E_ALIAS_NOT_FOUND |
El alias no está en la store | Crear con store_stripe_alias_tool |
E_DECRYPT_FAILED |
macOS Keychain inaccesible o passphrase distinto | Re-ingresar passphrase / re-crear keychain entry |
E_INVALID_KEY (en alias) |
sk_test_/sk_live_ malformado | Pegar de nuevo desde el dashboard |
E_LIVE_MODE_NOT_ALLOWED |
sk_live_* sin opt-in | Pasar allow_live_mode=true + live_mode_confirm_token="I acknowledge this affects real money" |
E_LIMIT_REACHED |
>16 webhook endpoints en la cuenta destino | Borrar los huérfanos: stripe webhooks list --limit=100 y purga manual |
E_SUPABASE_WRITE_FAILED |
PAT expirado / project_ref incorrecto | Revisar SUPABASE_ACCESS_TOKEN |
E_CONFIRMATION_REQUIRED |
Token literal incorrecto | Copiar el token exactamente como aparece en el mensaje de error |
Anexo B — .gitignore enforcement
La store cifrada en .claude/secrets/stripe_aliases.enc.json se añade a
.gitignore automáticamente la primera vez que se llama a
store_stripe_alias_tool. La skill lo verifica antes de cualquier acción.
Si por alguna razón está commiteada al repo, revoca todas las keys de
Stripe inmediatamente y rota — el archivo cifrado no debería bastar para
recuperarlas, pero asume compromiso.
Referencias
- Tool docs:
mcp__specbox-stripe__switch_stripe_account_tool - Alias store:
packages/specbox-stripe-mcp/src/specbox_stripe_mcp/lib/alias_store.py - Skills hermanas:
/stripe-connect(marketplace),/stripe-standard(no-Connect) - Tracking: SpecBox board
ff-bc73b5d69f91, US-STRIPE-SWITCH-ACCOUNT