Integración con Stripe y facturación al cliente
De principio a fin: desde un workspace vacío hasta tu primera factura Stripe, generada automáticamente desde una oferta aceptada en MSPercury. Cubre cuotas únicas (setup) junto con líneas mensuales / anuales de contrato, manejo de IVA / NIF / EIN / GST-HST, y la inversión del sujeto pasivo (reverse-charge) intra-UE.
💡 Lee esto antes de empezar. MSPercury no usa Stripe Connect ni facturación „on-behalf-of”. Conectas tu propia cuenta de Stripe con tu propia clave de API. El dinero fluye directamente entre tú y tu cliente — MSPercury solo ve la respuesta de la API, nunca el dinero, ni una comisión, ni un recargo. Somos un puro transportador de datos.
1. Prepara tu cuenta Stripe
Si todavía no tienes cuenta Stripe: stripe.com → registrarte, completar KYC (DNI + cuenta bancaria). 5–15 minutos. ¿Ya tienes cuenta? Salta al paso 2.
Activa Stripe Tax (muy recomendado)
Antes de empujar facturas vía MSPercury, activa Stripe Tax en el panel:
- Stripe Dashboard → More → Tax → Settings → Get started
- Define la dirección de origen (la dirección de tu negocio, igual que en MSPercury → Settings → Workspace)
- Añade tus registros fiscales — para MSPs en DE: tu USt-IdNr alemán (
DEXXXXXXXXX) + 19 % automático - Opcional: otros países donde estés registrado (Austria, Suiza…)
🟡 Lo que Stripe Tax hace por ti. Cálculo correcto del IVA en facturas nacionales (DE 19 %), reverse-charge automático para receptores B2B-UE con NIF válido (0 %, anotación en la factura), 0 % en facturas extracomunitarias. Sin Stripe Tax tienes que hacer todo manualmente. Stripe Tax cuesta 0,5 % por transacción facturada — en una factura de 100 € son 50 céntimos.
Crea una Restricted Key (en lugar de una Secret Key)
Recomendamos enérgicamente una Restricted Key con permisos mínimos en lugar de tu Secret Key completa:
- Stripe Dashboard → Developers → API keys → + Create restricted key
- Nombre:
MSPercury – Quote Push(o similar) - Permisos:
- Customers:
Write - Invoices:
Write - Subscriptions:
Write - Products:
Write - Prices:
Write - Tax IDs (Customers):
Write - Tax Rates:
Read - Charges, Payouts, Balance, Reporting: ❌ todo en
None
- Customers:
- Guardar → la clave empieza con
rk_test_…(modo test) ork_live_…(modo live)
🔒 ¿Por qué una Restricted Key? Si tu workspace MSPercury alguna vez se ve comprometido (admin sin 2FA, contraseña filtrada), un atacante con una Restricted Key no puede provocar pagos, ni mover devoluciones, ni rotar API keys. Solo puede hacer lo que MSPercury ya hace: crear facturas. Una Secret Key completa (
sk_live_…) en cambio permite básicamente todo — evítala cuando puedas.
⚠️ Modo test primero. Haz siempre tu onboarding con
rk_test_…. Las facturas test de Stripe no envían correos reales, no mueven dinero real, no escriben contabilidad real. Cambia ark_live_…solo cuando tu primer test esté limpio.
2. Configura los datos fiscales del workspace
Antes de pegar la clave en MSPercury, rellena estos dos campos en Settings → Workspace:
- País (Country): elige del desplegable (p. ej. Alemania)
- Tipo de identif. fiscal: se rellena automáticamente al cambiar el país (DE →
eu_vat, US →us_ein, CA →ca_gst_hst) - NIF / Identif. fiscal: tu propio
DEXXXXXXXXXpara MSPs alemanes
💡 ¿Dónde aparecen? En el pie de página de cada PDF (oferta, acuerdo, informe de CheckUp), automáticamente con la etiqueta habitual local: „USt-IdNr.: DEXXX” para workspaces alemanes, „VAT ID: ATXXX” para austriacos, „EIN: 12-3456789” para MSPs estadounidenses, „GST/HST: XXXXXXXXXRT0001” para canadienses. Sin etiquetas alemanas hardcodeadas. También se pasan a Stripe para que Stripe Tax pueda resolver la jurisdicción del proveedor.
3. Pega la clave en MSPercury
- Abre Settings → Integrations
- Pega la Restricted Key (
rk_test_…para el primer intento) - Click en Conectar Stripe
Qué pasa técnicamente:
- MSPercury llama a
stripe.accounts.retrieve()con tu clave para validarla y obtener los datos de la cuenta - En éxito: la clave se cifra AES-256-GCM at rest (mismo helper que para los secretos TOTP), nombre de cuenta + ID + modo (test/live) se cachean
- En error: el error de Stripe se muestra literal (p. ej. „No such account” → clave incorrecta, „Insufficient permissions” → la Restricted Key no tiene los permisos)
La pastilla de estado en el bloque de settings muestra:
- 🟢 Conectado + insignia
LIVE— listo para facturas reales - 🟡 Conectado + insignia
TEST— modo sandbox, sin correos / cargos reales - ⚪ No conectado — sin clave configurada
🔑 Rotar / reemplazar la clave. Estando conectado verás un bloque desplegable „Replace key”. Pega una nueva clave → la anterior se sobrescribe, una nueva llamada a
accounts.retrieve()la valida. Si sospechas un compromiso (laptop perdido, repo filtrado): reemplaza inmediatamente aquí, luego revoca la antigua en el Stripe Dashboard.
4. Configura los datos fiscales del cliente
Por cliente (/customers/[id]/edit):
- País: código ISO desde el desplegable
- Tipo de identif. fiscal: normalmente auto-rellenado por país (DE→
eu_vat, US→us_ein, CA→ca_gst_hst) - Identif. fiscal: el número real, p. ej.
DE123456789,12-3456789,123456789RT0001 - Dirección: completa con
calle + código postal + ciudad
💡 ¿Por qué tan granular? Sin país + tipo Stripe Tax no puede resolver la jurisdicción del receptor. Resultado: 0 % de IVA en facturas porque Stripe no sabe si es una entrega nacional (DE 19 %) o intra-UE con reverse-charge (0 %, el receptor declara). Sin info de país son indistinguibles para Stripe.
⚠️ En el push a Stripe. MSPercury busca primero
customers.search({ query: 'metadata.mspercury_customer_id:"…"' })para ver si el cliente ya existe en tu cuenta Stripe. Si sí: dirección + ID fiscal se sincronizan. Si no: se crea un cliente nuevo contax_id_datay dirección. Hacer push dos veces no crea duplicados.
5. Crea una oferta y haz que la acepten
Ver Getting started para crear ofertas desde cero. Lo importante para Stripe es el periodo de facturación de cada línea:
| Periodo MSPercury | Mapeo Stripe | Cuándo se envía |
|---|---|---|
| Único | Invoice (sola) O InvoiceItem en la primera factura de la suscripción (mixto) | Inmediatamente, una vez |
| Mensual | Subscription con interval=month | Primera factura ya, luego cada mes |
| Anual | Subscription con interval=year | Primera factura ya, luego anual |
💡 Elige el periodo deliberadamente. Las cuotas de setup deberían ser „único”. Una licencia RMM es „mensual”. Una licencia de backup con contrato anual es „anual”. El editor de ofertas te deja elegir por línea. Si te equivocas: edición post-aceptación está disponible (registro live + MRR del dashboard sincronizan; el PDF firmado queda como referencia auditable inmutable).
Una vez el cliente acepta la oferta vía la share-page (o la marcas aceptada manualmente), aparece el bloque violeta de Stripe.
6. Push a Stripe — qué sucede realmente
En el detalle de una oferta aceptada aparece el bloque violeta „Crear factura en Stripe”. Antes de hacer click, MSPercury te muestra explícitamente qué se creará:
Se creará en Stripe
├─ [Subscription] 6× mensual recurrente + 2× único en la primera factura
│ — Stripe rota las facturas siguientes automáticamente
└─ [Subscription] 1× anual recurrente
El click ejecuta:
- Find-or-create Stripe customer (con dirección + tax-id-data)
- Por cada intervalo recurrente no vacío:
subscriptions.create()con los items correspondientes - Líneas únicas: se cuelgan en la primera factura de la primera subscription vía
add_invoice_items— el cliente recibe un correo cubriendo setup + primer periodo - Footer en cada factura Stripe: „MSPercury reference: Q-2026-XXXX” — vincula la factura a su oferta de origen a simple vista
Lo que Stripe hace autónomamente después:
- Rota las facturas mensuales / anuales siguientes (sin segunda llamada de nuestra parte)
- Envía correos de hosted-invoice con tu branding (¡configura logo + color en el Stripe Dashboard!)
- Permite al cliente self-service: cambiar método de pago, cancelar, descargar facturas pasadas
- Aplica la lógica Stripe Tax en cada factura recurrente (el reverse-charge sigue activo mientras el NIF esté vigente)
🟢 Toggle „Enviar ahora”. Para ofertas únicas puedes elegir: dejar la factura como draft en el Stripe Dashboard o enviar inmediatamente. Para ofertas con suscripción la primera factura siempre se envía — Stripe la finaliza + emaila al
subscriptions.create(). No existe el concepto de „draft subscription” en la API de Stripe. Si no lo quieres así: no clickees, o pausa / borra la subscription en el Stripe Dashboard después.
🟡 Restricción de cantidad. Los items de subscription en Stripe solo aceptan cantidades enteras. Las líneas con cantidades fraccionarias („1,5 horas”) se redondean al entero más cercano (
Math.round(...)). Para tarifas por hora recomendamos: convertir a minutos („90 minutos” con precio unitario por minuto), o añadir una línea separada „pack 1,5 h”.
7. Reverse-charge intra-UE
Stripe Tax aplica la regla de reverse-charge automáticamente, siempre que:
- Tu workspace esté registrado con país + NIF en DE/UE
- El cliente esté en otro estado miembro UE (no nacional)
- El cliente tenga tipo
eu_vatcon número válido (p. ej.FR12345678901)
En ese caso:
- Factura Stripe: 0 % IVA, anotación „Reverse charge — Art. 196 VAT Directive”
- PDF de oferta MSPercury: banner amarillo encima de las líneas (Art. 196 Directiva IVA / §13b UStG, en el idioma del cliente)
💡 ¿Y si el cliente no tiene NIF? Entonces no es un caso B2B-reverse-charge, es B2C — Stripe aplica tu tipo local de IVA (DE 19 %), y tienes que liquidar el IVA en el país receptor por tu cuenta (régimen One-Stop-Shop / OSS). Eso normalmente no es lo que quieres con clientes MSP. Si necesitas el camino reverse-charge, pide el NIF activamente — y valídalo con VIES antes de meterlo.
⚠️ CH y UK. Suiza (
ch_vat) y UK (gb_vat) no son UE — el reverse-charge no aplica. Configura Stripe Tax por separado para esos países si tienes muchos clientes allí.
8. Tropezones habituales
| Síntoma | Causa | Solución |
|---|---|---|
| Stripe rechaza la clave al guardar | Clave incorrecta o Restricted Key con permisos insuficientes | Revisa los permisos en Stripe Dashboard, crea una nueva con los scopes listados arriba |
| Primera factura sale al 0 % IVA aunque sea nacional | El workspace no tiene país / tipo fiscal | Settings → Workspace → rellenar país + tipo fiscal |
| El reverse-charge no se aplica | El cliente no tiene tipo eu_vat o el NIF está vacío | Customer edit → rellenar país + tipo + NIF, luego push de nuevo |
| Factura duplicada al segundo click | Idempotencia aún no implementada (roadmap) | Anular manualmente la subscription / factura duplicada en Stripe Dashboard |
| „Customer has no email address” | Email del cliente vacío en MSPercury | Customer edit → rellenar email — Stripe lo necesita para enviar la hosted-invoice |
| Factura enviada pero el cliente no recibe nada | Hipo de Stripe Tax o de la cuenta con la hosted-invoice | Stripe Dashboard → Invoices → seleccionar esa factura → „Send again” |
| Llega la primera factura del sub pero el cliente cree que es TODO | El hecho de que Stripe va a facturar otra vez no estaba claro | Personaliza el copy de la hosted-invoice en Stripe Dashboard → Branding mencionando „suscripción, facturación recurrente automática” |
9. Lo que MSPercury no hace
División clara para que sepas qué lado posee qué:
- ❌ MSPercury no genera certificados fiscales, cierres anuales, declaraciones de IVA — eso lo sigue haciendo tu asesor o tu herramienta contable (conector DATEV en la roadmap)
- ❌ MSPercury no valida los NIF — eres responsable de validarlos vía VIES antes de meterlos
- ❌ MSPercury no anula facturas Stripe — si un cliente se va, pausa / cancela la subscription en Stripe Dashboard + anula la factura abierta
- ❌ MSPercury no archiva facturas Stripe — viven en tu cuenta Stripe, eres responsable de la retención GoBD-compliant (Stripe tiene exports)
- ❌ MSPercury no maneja refunds, chargebacks, disputas — todo en el Stripe Dashboard
- ❌ MSPercury no conoce tu saldo Stripe, payouts, carga fiscal — solo vemos IDs de factura, nunca flujos de dinero
Lo que MSPercury sí hace:
- ✅ Convierte cada oferta aceptada en una factura (o subscription) Stripe en tu cuenta
- ✅ Sincroniza datos maestros del cliente + IDs fiscales en Stripe en cada push
- ✅ Estampa footer / metadata en cada factura Stripe con la referencia de la oferta — puedes saltar de Stripe Dashboard a la oferta original
- ✅ Mantiene la API key cifrada y segura dentro de tu workspace, nunca la comparte con terceros
10. Roadmap
Lo que viene:
- Idempotencia: un segundo click en „Crear factura Stripe” se detecta, sin duplicados
- IDs de Stripe Subscription en la fila de la oferta: para que
/quotes/[id]muestre „ya enviada a Stripe — sub_…”, con enlace directo al Dashboard - Webhook sync: cuando una subscription Stripe se cancela, el MRR del dashboard se actualiza automáticamente
- Lexware Office, sevDesk, Polar.sh: conectores alternativos para MSPs que no usan Stripe — ver roadmap
¿Falta algo concreto? Comunidad Discord, canal #stripe-billing. Lucas lee allí.