Auto-facturación con Stripe
Emite facturas automáticamente desde los cobros de Stripe Connect — captura de NIF en el Checkout, umbral de factura simplificada, exigir NIF y qué cobros se derivan a revisión manual.
Cuando conectas Stripe mediante Stripe Connect, Factuarea puede emitir una
factura automáticamente por cada cobro exitoso: el cobro se convierte en una
factura con status: sent, se da de alta en VeriFactu y se le registra un
Payment. El flujo es idempotente de extremo a extremo, así que un webhook
reentregado nunca produce una factura duplicada.
Lo alimentan dos flujos:
- Flujo A — un cobro que paga una factura de Factuarea ya existente (una Checkout Session que Factuarea creó desde un enlace de pago). La factura ya existe; el cobro la marca como pagada.
- Flujo B — un cobro espontáneo sin factura previa (un Payment Link que el comercio creó en su propio Dashboard de Stripe, o cualquier otro cobro de Connect). Factuarea crea la factura a partir del cobro.
La configuración se lee y escribe a través de los endpoints v1 a nivel de empresa:
- Obtener la configuración de auto-facturación
(
stripe_autoinvoicing:read). - Actualizar la configuración de auto-facturación
(
stripe_autoinvoicing:write). - Listar cobros auto-facturados
(
stripe_autoinvoicing:read). - Listar rectificativas auto-facturadas
(
stripe_autoinvoicing:read).
Si gestionas varias tiendas con cuentas de Stripe distintas, cada cuenta tiene su propia serie y su propia configuración — consulta Varias tiendas.
La auto-facturación está limitada por el módulo de integración con Stripe de
tu plan y viene desactivada por defecto — actívala explícitamente con
enabled: true.
Qué expone la API de Stripe. Configuración de auto-facturación a nivel de empresa (una comodidad heredada del modelo de tienda única — la fuente de verdad real es la configuración por cuenta conectada, ver Varias tiendas), cuentas conectadas, cobros auto-facturados, rectificativas y payouts para la conciliación bancaria.
Varias tiendas
Un negocio puede operar varias "tiendas" o líneas (una tienda física + un curso
online) con cuentas de Stripe distintas (Stripe Connect) y querer numeración
de facturas independiente para cada una (TIENDA-2026-…, CURSOS-2026-…).
Factuarea modela cada cuenta de Stripe que conectas como una cuenta conectada:
cada Account Link que completas añade una cuenta — nunca sobrescribe la
anterior — y los cobros de cada cuenta se enrutan a la serie y la configuración
de esa cuenta.
Cada cuenta conectada lleva:
- una serie (
series_id) usada para las facturas auto-creadas a partir de sus cobros —nullsignifica que se usa la serie de facturas por defecto de la empresa; - su propia configuración de auto-facturación (
autoinvoicing_enabled,simplified_threshold_cents,require_nif,refunds_enabled,subscription_autoinvoicing_enabled) — toda regla fiscal de esta página aplica por cuenta.
Cuando llega un webhook, Factuarea resuelve la cuenta de Stripe (acct_xxx) a su
cuenta conectada y emite la factura en la serie de esa cuenta, con la política
fiscal de esa cuenta — de modo que dos tiendas producen facturas en dos series de
numeración separadas y correctas.
Las cuentas nuevas nacen seguras
Una cuenta recién conectada no hereda la configuración de otra cuenta: nace con los mismos valores por defecto seguros que un alta nueva — auto-facturación desactivada, umbral 400 €, "exigir NIF" desactivado, devoluciones activas, suscripciones desactivadas — y sin serie (cae en la serie por defecto de la empresa hasta que le asignes una). Configúrala explícitamente antes de que emita nada.
Endpoints v1 por cuenta
Gestiona las cuentas bajo el recurso connected-accounts (mismos scopes
stripe_autoinvoicing:read|write; la identidad es el id de la cuenta, un UUID v7):
- Listar cuentas conectadas
(
stripe_autoinvoicing:read). - Obtener una cuenta conectada
(
stripe_autoinvoicing:read). - Actualizar una cuenta conectada
— nombre,
series_id(envíanullpara limpiarla) y la configuración por cuenta (stripe_autoinvoicing:write). - Desconectar una cuenta conectada
(
stripe_autoinvoicing:write).
# Asignar la serie CURSOS y activar la auto-facturación en una tienda
curl -X PUT https://api.factuarea.com/v1/connected-accounts/0192f3a4-… \
-H "Authorization: Bearer fact_test_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0192f3a4-…" \
-d '{
"series_id": "0192aaaa-…",
"autoinvoicing_enabled": true
}'Desconectar una cuenta conserva sus facturas ya emitidas y su histórico; los
webhooks posteriores se registran sin procesar. Referenciar el id de una
cuenta que pertenece a otra empresa devuelve 404 (connected_account_not_found)
— el aislamiento multi-tenant nunca filtra la existencia.
El endpoint a nivel de empresa mientras tienes una tienda
Los endpoints de configuración
a nivel de empresa de arriba siguen válidos mientras tienes exactamente una
cuenta conectada: el GET devuelve la configuración efectiva de esa única cuenta
y el PUT hace de proxy hacia ella (escribe en la configuración de la cuenta,
nunca una copia duplicada a nivel de empresa).
En cuanto conectas una segunda cuenta, la configuración a nivel de empresa ya
no puede responder a "¿qué cuenta?". Tanto el GET como el PUT devuelven
entonces 422 (per_account_config_required, mensaje en español) apuntándote a
los endpoints por cuenta — Factuarea nunca escribe en dos sitios, así que no hay
divergencia entre una configuración a nivel de empresa y las cuentas.
Una sola fuente de verdad. La configuración por cuenta es el único lugar
donde viven los ajustes. El endpoint a nivel de empresa es una comodidad que hace
de proxy a la cuenta única; nunca guarda una copia separada, de modo que leer y
escribir siempre coinciden. Con dos o más cuentas, usa connected-accounts/{account}
directamente.
Factura ordinaria o simplificada
Una factura española necesita el NIF del destinatario para emitirse como factura ordinaria (F1). Un cobro B2C sin NIF es justo el caso que la normativa resuelve con una factura simplificada (F2). Factuarea decide cuál emitir a partir de los datos que trae el cobro más tu política fiscal:
| Situación | Factura emitida |
|---|---|
| Se captura un NIF válido en el Checkout, o el cliente resuelto ya tiene un NIF en su ficha | Ordinaria (F1) |
| Sin NIF, total del cobro igual o por debajo del umbral y "exigir NIF" desactivado | Simplificada (F2) |
| Sin NIF y (total por encima del umbral o "exigir NIF" activado) | Revisión manual — no se auto-emite ninguna factura |
Un NIF capturado se valida contra el formato español (NIF/NIE/CIF). Un NIF con formato no válido cuenta como sin NIF, así que nunca se emite una F1 con datos basura.
Los cobros derivados a revisión manual no se pierden: quedan registrados en el log de la integración para que emitas la factura a mano. La auto-facturación continúa con el resto — un cobro en revisión nunca hace fallar el webhook.
El tope legal absoluto de una factura simplificada es de 3.000 €, garantizado por el propio dominio de facturación: un cobro sin NIF por encima de 3.000 € siempre va a revisión manual, sea cual sea el umbral configurado.
Capturar el NIF en el Checkout
Para que un cliente que sí tiene NIF pueda aportarlo, las Checkout Sessions que
crea Factuarea (Flujo A) activan la recogida del identificador fiscal de
Stripe. El cliente puede introducir su es_cif/eu_vat al pagar, y ese NIF
encamina hacia la F1.
El NIF también se lee de cualquier checkout.session.completed entrante:
- de
customer_details.tax_ids(el campo estándar de Stripe), y - de los campos personalizados de los Payment Links que el comercio construye
en su propio Dashboard de Stripe — Factuarea busca un campo cuya clave parezca
un identificador fiscal (
nif,dni,cif,vat,tax).
Un cobro que llega solo como payment_intent.succeeded (sin Checkout) no trae
ningún NIF capturado, pero aún puede ser una F1 si el cliente se resuelve por
email y ya tiene un NIF en su ficha.
El umbral
simplified_threshold_cents es el importe en céntimos igual o por debajo del
cual un cobro sin NIF se auto-emite como factura simplificada. Su valor por
defecto es 40000 (400 €) y acepta cualquier valor en el rango [0, 300000]
(0–3.000 €).
Un valor por defecto conservador de 400 € es deliberado: el tope de 3.000 € solo es legal en sectores tasados concretos, y Factuarea no conoce tu sector — sube el umbral únicamente si tu actividad lo permite.
curl -X PUT https://api.factuarea.com/v1/stripe-autoinvoicing/config \
-H "Authorization: Bearer fact_test_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0192f3a4-…" \
-d '{
"enabled": true,
"simplified_threshold_cents": 100000,
"require_nif": false
}'Ambos campos fiscales son opcionales: si omites simplified_threshold_cents o
require_nif, se conservan sus valores actuales. Un umbral fuera del rango
devuelve 422 (validation_error).
Exigir un NIF
require_nif (por defecto false) tiene dos efectos coherentes:
- En las Checkout Sessions que crea Factuarea, el identificador fiscal se marca
como obligatorio (
if_supported), de modo que se le solicita al cliente. - En la decisión de arriba, veta la F2: un cobro sin NIF va a revisión manual en lugar de convertirse en factura simplificada.
Actívalo cuando tu empresa no quiera nunca facturas simplificadas automáticas: cada cobro pasa entonces a tener NIF (F1) o a esperarte en revisión manual.
Las facturas auto-emitidas son fiscalmente reales e irreversibles (se crea
el registro de Alta de VeriFactu). Valida tu política fiscal primero con una
clave fact_test_: en el sandbox el registro de VeriFactu
se crea localmente y nunca se transmite a la AEAT, así que puedes ejercitar la
decisión F1/F2/revisión sin riesgo antes de pasar a producción.
El evento saliente
Cada factura auto-creada — F1 o F2 — emite el evento
invoice.auto_created y un
evento payment.received. En una factura simplificada el payload lleva
client_id: null (sin destinatario), de modo que un receptor de webhooks puede
distinguir la F1 de la F2.
Desglose real de IVA con Stripe Tax
Si usas Stripe Tax, cada cobro ya trae el desglose fiscal real por línea — el tipo, la base imponible y, cuando aplica, la causa por la que una línea está exenta o sujeta a inversión del sujeto pasivo. Factuarea espeja ese desglose en la factura en lugar de aplanarlo todo a un único tipo por defecto.
El webhook del Checkout no incluye las líneas, así que Factuarea hace una segunda llamada de solo lectura a la API en tu nombre para recuperarlas con sus impuestos, y mapea cada línea:
| Dato de Stripe Tax | Línea de la factura |
|---|---|
rate.percentage | el tipo de IVA de la línea (vat_rate), tal cual — nunca se recalcula |
taxable_amount | la base imponible de la línea (precio unitario = base ÷ cantidad) |
taxability_reason zero_rated / product_exempt / customer_exempt | línea exenta al 0 % |
taxability_reason reverse_charge | línea con inversión del sujeto pasivo (ISP) al 0 % |
Así, un cobro con IVA mixto (p. ej. 21 % de consultoría + 10 % de un libro) se convierte en una factura con dos líneas reales, cada una a su tipo, y el desglose multi-IVA llega hasta el registro de VeriFactu.
El IVA nunca se recalcula — Stripe ya lo calculó, y recalcularlo introduciría desviaciones de céntimos. Factuarea toma el tipo y la base imponible directamente de Stripe Tax.
Cuando no hay Stripe Tax (no lo has activado en tu cuenta de Stripe) no cambia nada: cada línea recurre al IVA por defecto de tu empresa, igual que antes. Una empresa sin IVA por defecto configurado recurre al 0 % — nunca a un 21 % fantasma.
Líneas reales
Cuando un cobro trae varias líneas (varios productos o conceptos), aparecen como líneas reales e independientes en la factura — cada una con su descripción, cantidad y precio — en lugar de colapsarse en una sola. Son líneas libres (no enlazadas a tu catálogo de productos).
Esto es ortogonal al tipo de factura: la decisión F1/F2 de arriba elige el tipo, el mapeo de líneas elige las líneas — tanto una factura ordinaria como una simplificada obtienen las mismas líneas reales.
Un cobro que llega solo como payment_intent.succeeded (sin Checkout Session,
por lo que no hay líneas recuperables), o un cobro cuya recuperación de líneas
falla tras los reintentos, sigue produciendo una factura: recurre a una sola
línea con el IVA por defecto. La factura nunca se pierde por un detalle no
esencial.
Antes de emitir, Factuarea valida el total: el total derivado de las líneas
espejadas (suma de subtotal + IVA por línea, en EUR) debe coincidir con el
importe realmente cobrado, dentro de una pequeña tolerancia de redondeo (±1
céntimo por línea, mínimo ±0,05 €). Si no coincide, el cobro se deriva a
revisión manual (total_mismatch) en lugar de emitir una factura cuyo total
diverja del cobro real — el webhook responde correctamente igualmente.
Cobros en otra moneda
Un cobro en una moneda distinta del EUR ya no se descarta. Factuarea lo convierte a EUR usando el tipo de cambio de referencia del Banco Central Europeo (BCE) de la fecha de pago y emite la factura en euros — base, IVA y total, y el registro de VeriFactu/AEAT, todo en EUR (Art. 12.1 RD 1619/2012: la cuota de IVA debe consignarse en euros).
- Un cobro en EUR pasa intacto.
- Un cobro ≠EUR con tipo disponible se convierte; la traza de la conversión — importe y moneda originales, tipo BCE y fecha del tipo — se escribe en las notas de la factura y en el registro de integración para auditoría fiscal.
- Un cobro en una moneda sin tipo BCE disponible no se auto-factura: se deriva a revisión manual y el webhook responde correctamente igualmente. Factuarea nunca inventa un tipo.
Los tipos del BCE se cachean a diario (sin tabla de base de datos adicional), así que varios cobros ≠EUR del mismo día comparten una sola consulta del tipo.
Emitir la factura en la moneda original (opción B) queda intencionadamente fuera de alcance — Factuarea siempre convierte a EUR (opción A).
Devoluciones y facturas rectificativas
Una factura emitida es fiscalmente irreversible — nunca se borra ni se anula
una vez pagada. La única forma legal de deshacerla es una factura rectificativa.
Por eso, cuando Stripe devuelve un cobro que Factuarea facturó, Factuarea cierra
el ciclo fiscal por ti: el webhook charge.refunded genera automáticamente una
factura rectificativa enlazada (con su propio registro R de VeriFactu), sin
rectificar a mano.
Lo controla refunds_enabled (por defecto true). Solo actúa mientras la
auto-facturación está activada — el gating es enabled && refunds_enabled. Una
empresa que nunca activó la auto-facturación no ve ningún cambio.
| Devolución | Rectificativa emitida |
|---|---|
Total (refunded: true) | Una rectificativa total que refleja toda la factura original como líneas negativas |
Parcial (amount_refunded < amount) | Una rectificativa partial con una única línea negativa por el importe devuelto, al tipo impositivo de la línea original |
La rectificativa se emite siempre por diferencias (AEAT TipoRectificativa: I),
porque una devolución es un abono con importes negativos. Lleva el motivo de
corrección devolucion; si la original es una factura simplificada (F2), la
rectificativa se emite como R5 automáticamente.
La factura original se localiza por dos caminos — por el metadato
factuarea_invoice del cobro (Flujo A) o por el UUID determinista derivado del
payment_intent (Flujo B) — así que las devoluciones de cobros emitidos antes
de que existiera esta función también se rectifican.
La idempotencia es por devolución individual. Stripe reenvía
charge.refunded con el amount_refunded acumulado, pero Factuarea se basa
en el id de cada devolución individual (re_xxx): cada una produce como
máximo una rectificativa. Un evento reentregado, o una segunda devolución
parcial, nunca abonan por duplicado. Una devolución cuya factura original no se
pueda localizar, que no esté en un estado rectificable (sent/paid) o que ya
esté rectificada queda registrada en el log de la integración para revisión
manual — nunca hace fallar el webhook.
Cada rectificativa automática emite el evento
invoice.corrective_auto_created
(que lleva la rectificativa, la factura original, el refund_id de origen y el
provider), y puedes listarlas con
Listar rectificativas auto-facturadas.
Para recibir devoluciones debes habilitar el evento charge.refunded en el
endpoint de webhook de Connect en el Dashboard de Stripe. Como con la
auto-facturación, valida el flujo primero con una clave fact_test_: en el
sandbox el registro R de VeriFactu se crea localmente y
nunca se transmite a la AEAT. Para desactivarlo, pon refunds_enabled: false —
las devoluciones quedan entonces en el log de la integración para gestión
manual, el comportamiento actual.
Ciclos de suscripción
Si cobras con Stripe Billing en tu cuenta conectada — suscripciones recurrentes mensuales o anuales — Factuarea puede emitir una factura automáticamente por cada ciclo cobrado. Cada renovación que cobra Stripe produce su propia factura conforme a VeriFactu, espejando el desglose real (líneas, periodo, impuestos) que Stripe ya calculó, igual que los cobros únicos.
Es un toggle separado, subscription_autoinvoicing_enabled (por defecto
false), por encima del flag general enabled. Ambos deben estar activos para
que un ciclo se facture — activar solo las suscripciones no hace nada mientras la
auto-facturación está globalmente desactivada.
curl -X PUT https://api.factuarea.com/v1/stripe-autoinvoicing/config \
-H "Authorization: Bearer fact_test_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0192f3a4-…" \
-d '{
"enabled": true,
"subscription_autoinvoicing_enabled": true
}'Qué ciclos se facturan
Factuarea factura el ciclo de facturación estándar y deriva el resto a revisión
o lo ignora, según el billing_reason de Stripe:
billing_reason | Qué hace Factuarea |
|---|---|
subscription_create (primer ciclo) | Se factura |
subscription_cycle (cada renovación) | Se factura |
subscription_update, subscription_threshold (prorrateos standalone) | Revisión manual — se registra en el log de la integración, no se auto-factura |
manual, upcoming, quote_accept, otros | Se ignora con un log informativo |
- Los trials no facturan. Un ciclo cuyo
invoice.totales 0 € (un periodo de prueba, o un ciclo cubierto íntegramente por crédito) no emite factura; el primer cobro real tras el trial se factura con normalidad. - Los prorrateos standalone (un upgrade/downgrade cobrado por su cuenta, fuera del ciclo regular) no se auto-facturan hoy — van a revisión manual para que decidas. El ciclo regular siguiente se factura como siempre.
- La decisión F1/F2 es la misma. El NIF del destinatario se lee de los
customer_tax_idsde la invoice (más la ficha del cliente resuelto); con NIF el ciclo es una factura ordinaria (F1), sin él e igual o por debajo del umbral una simplificada (F2), y sin él por encima del umbral (o con "exigir NIF" activado) va a revisión manual — idéntico a las reglas de la sección de decisión. Se aplican el mismo espejo de líneas/IVA de Stripe Tax, la conversión a EUR y la validación de total.
Cada ciclo es su propia factura
Un ciclo de suscripción se convierte en una factura suelta — no crea ni
toca ninguna factura recurrente de Factuarea. Las dos son independientes:
Stripe lleva la cadencia y cada invoice.paid produce una factura.
Evita la doble facturación. Si ya modelas la suscripción del mismo cliente como una factura recurrente manual en Factuarea, activar la auto-facturación de suscripciones para esa suscripción de Stripe producirá dos facturas por periodo — una de tu plantilla recurrente y otra del ciclo de Stripe. Elige una sola fuente por cliente: detén la factura recurrente manual o deja este toggle desactivado para esas suscripciones.
El evento saliente
Una factura de ciclo de suscripción emite un evento distinto,
invoice.subscription_auto_created
(además de payment.received), de modo que un receptor de webhooks puede
distinguir los ciclos de suscripción de los cobros únicos. Un cobro único sigue
emitiendo invoice.auto_created como antes. El listado de cobros auto-facturados
(Listar cobros auto-facturados)
expone el contexto de suscripción (subscription_id, stripe_invoice_id,
period_start, period_end) para los cobros de ciclo (null para cobros únicos),
y un filtro opcional origin (subscription/oneshot).
La idempotencia es por ciclo de facturación. Factuarea se basa en cada id de
invoice de Stripe (in_xxx): un evento reentregado, o un segundo evento del
mismo ciclo, produce como máximo una factura. Los ciclos históricos no se
facturan retroactivamente — solo se facturan los ciclos cobrados después de
que actives el toggle; los replays de eventos invoice.paid antiguos se ignoran.
Para recibir los ciclos de suscripción debes habilitar el evento
invoice.paid en el endpoint de webhook de Connect en el Dashboard de
Stripe. Como siempre, valida el flujo primero con una clave fact_test_: en el
sandbox el registro de Alta de VeriFactu se crea localmente
y nunca se transmite a la AEAT.
Valores por defecto de un vistazo
| Campo | Por defecto | Efecto del valor por defecto |
|---|---|---|
enabled | false | Auto-facturación desactivada — no se emite nada hasta que la actives |
simplified_threshold_cents | 40000 (400 €) | Los cobros sin NIF de hasta 400 € se convierten en F2 |
require_nif | false | Se permiten facturas simplificadas; el identificador fiscal se ofrece pero no se exige |
refunds_enabled | true | Una devolución de Stripe genera una factura rectificativa automática (mientras la auto-facturación está activada) |
subscription_autoinvoicing_enabled | false | Los ciclos de suscripción de Stripe no se auto-facturan hasta que lo actives (requiere también enabled) |
Con estos valores por defecto, el único cambio de comportamiento una vez activada
la auto-facturación es que un cobro sin NIF de hasta 400 € se convierte en factura
simplificada en lugar de esperar en revisión, y una devolución genera su factura
rectificativa automáticamente. Los cobros con NIF se comportan exactamente igual
que antes. Los ciclos de suscripción quedan desactivados hasta que optes por ellos
con subscription_autoinvoicing_enabled.
Glosario
Términos fiscales y de dominio españoles usados en toda la API de Factuarea — NIF, VeriFactu, AEAT, FacturaE, Modelo 303/347, series, rectificativa, huella, CSV y más.
Payouts y conciliación bancaria
Cómo Factuarea ingiere los payouts de Stripe, los vincula con los cobros que agrupan, los concilia contra tu extracto Norma 43 y emite el evento payout.reconciled.