Saltearse al contenido

Facturar en España

IVA, exenciones e inversión del sujeto pasivo

Cada línea declara su IVA con el código del catálogo de impuestos:

{
"descripcion": "Servicio de soporte mensual",
"cantidad": 1,
"precio_unitario": 100.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
}
codigo_impuestoTarifaCuándo se usa
ES_IVA_2121 %Tipo general
ES_IVA_1010 %Tipo reducido
ES_IVA_44 %Tipo superreducido
ES_IVA_0—Exenta (art. 20 LIVA)
ES_NO_SUJETO_LOC—No sujeta por reglas de localización (art. 69 LIVA)
ES_ISP_UE—Inversión del sujeto pasivo (art. 196 Directiva 2006/112/CE)

Consúltalos desde la API, con la calificación que cada uno lleva ante la AEAT:

Ventana de terminal
curl https://olympus.atharix.com/api/v1/catalogs/tax-rates -H "X-API-Key: $OLYMPUS_API_KEY"
{
"data": [
{ "codigo_impuesto": "ES_IVA_21", "tarifa": 21.0, "nombre": "IVA general 21%", "calificacion_aeat": "S1" },
{ "codigo_impuesto": "ES_IVA_0", "tarifa": 0.0, "nombre": "Exenta (art. 20 LIVA)", "calificacion_aeat": "E1" },
{ "codigo_impuesto": "ES_ISP_UE", "tarifa": 0.0, "nombre": "Inversión del sujeto pasivo", "calificacion_aeat": "N2" }
]
}

Una línea sin cuota tiene que decir por qué

Sección titulada «Una línea sin cuota tiene que decir por qué»

Esta es la diferencia importante con Ecuador. En España no vale enviar 0 % a secas:

// ❌ 422 missing_tax_code
"impuestos": [{ "tarifa": 0 }]
// ✅
"impuestos": [{ "codigo_impuesto": "ES_IVA_0" }]

El motivo es legal: exenta, no sujeta e inversión del sujeto pasivo se declaran distinto ante la AEAT (E1, N2) y obligan a imprimir menciones legales diferentes en la factura. Si Olympus eligiera una por ti, la factura podría estar mal.

"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]

Olympus deduce la tarifa y calcula la cuota. Es lo más robusto.

"impuestos": [{ "tarifa": 21 }]

Solo funciona para los tipos con cuota (21, 10, 4): una tarifa 0 no dice cuál de los tres casos sin cuota es, así que se rechaza.

"impuestos": [
{ "codigo_impuesto": "ES_IVA_21", "tarifa": 21, "base_imponible": 100.00, "valor": 21.00 }
]

Olympus comprueba que cuadra y rechaza la emisión si no (422 totals_mismatch, tolerancia 0,01).

Por línea:

base = (cantidad × precio_unitario) − descuento
IVA = base × tarifa ÷ 100 (redondeado a 2 decimales, medio hacia arriba)

Y la factura:

total_sin_impuestos = Σ bases
iva = Σ IVA de cada línea
importe_total = total_sin_impuestos + iva + recargo de equivalencia

Cada línea lleva el suyo, sin problema:

{
"items": [
{
"descripcion": "Consultoría",
"cantidad": 1, "precio_unitario": 100.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
},
{
"descripcion": "Manual técnico",
"cantidad": 1, "precio_unitario": 30.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_4" }]
}
],
"totales": { "total_sin_impuestos": 130.00, "importe_total": 152.20 }
}

El registro que se envía a la AEAT lleva el desglose agrupado por tipo y calificación.

En importe, y reducen la base antes del IVA:

{
"descripcion": "Licencia anual",
"cantidad": 2,
"precio_unitario": 50.00,
"descuento": 10.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
}
base = (2 × 50,00) − 10,00 = 90,00
IVA = 90,00 × 0,21 = 18,90

Ni la retención de IRPF ni el recargo de equivalencia son impuestos de línea: van en el primer nivel del payload y afectan a toda la factura. Ver Retención de IRPF y Recargo de equivalencia.