Saltearse al contenido

Facturar en España

Emitir una factura

POST /api/v1/invoices/issue · scope invoices:write · responde 201

El payload mínimo es corto: un comprador y una línea con su IVA.

{
"comprador": { "identificacion": "12345678Z", "razon_social": "CLIENTE EJEMPLO S.L." },
"items": [
{
"descripcion": "Servicio de soporte",
"cantidad": 1,
"precio_unitario": 100.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
}
]
}
CampoObligatorioPor defectoNotas
comprador✅—Sin identificación se emite una factura simplificada
items✅—Al menos una línea, cada una con su IVA
referencia_externa——Envíala siempre. Tu identificador de la venta
fecha_emision—Hoy en EspañaYYYY-MM-DD. No puede ser futura
fecha_vencimiento——Para ventas a crédito
retencion——Retención de IRPF en porcentaje: 1, 2, 7, 15 o 19
recargo_equivalencia—falseRepercutir recargo al comerciante minorista
totales——Si lo envías, se comprueba
moneda—EUREspaña admite otras divisas del BCE
enviar_email—trueEnviar el PDF al comprador
notas——Texto libre interno
{
"identificacion": "12345678Z",
"razon_social": "CLIENTE EJEMPLO S.L.",
"email": "facturas@ejemplo.es",
"telefono": "600123456",
"direccion": "Gran Vía 28, Madrid",
"pais": "FR"
}
CampoObligatorioNotas
identificacion—NIF, CIF o NIE. Vacío emite una factura simplificada
razon_social—Obligatoria si no hay identificación
pais—ISO alfa-2. Vacío = España. Obligatorio si la identificación no es española
email—Necesario para que le llegue el PDF
telefono, direccion—Salen en la factura

No hay tipo_identificacion: eso es del SRI ecuatoriano. En España lo que decide cómo se identifica al comprador ante la AEAT es el país. Ver Clientes de otros países.

Sin identificación, la factura se emite como simplificada (tipo F2) y usa la serie T:

{ "comprador": { "razon_social": "Cliente mostrador" }, "items": [ … ] }

La normativa limita su importe; por encima de ese umbral hay que identificar al comprador.

Si el NIF no corresponde a ningún cliente del negocio, Olympus crea el contacto automáticamente. Se desactiva por clave, desde Configuración → Integraciones.

{
"codigo_principal": "SRV-001",
"descripcion": "Servicio de soporte mensual",
"cantidad": 1,
"unidad_medida": "Unidad",
"precio_unitario": 100.00,
"descuento": 0,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
}
CampoObligatorioNotas
descripcion✅Lo que ve el cliente en la factura
cantidad✅Mayor que cero
precio_unitario✅Sin impuestos, dos decimales
impuestos✅Obligatorio. Cada línea declara su IVA
codigo_principal—Si coincide con el SKU de un producto, la línea se enlaza a él
descuento—En importe, no en porcentaje
unidad_medida—Por defecto Unidad

Si codigo_principal coincide con el SKU de un producto de Olympus, la línea queda enlazada y, si es un bien, descuenta stock. Sin existencias, la emisión falla con 422 insufficient_stock.

{ "total_sin_impuestos": 100.00, "descuento": 0, "importe_total": 121.00 }

Opcional pero muy recomendable: Olympus compara con lo que calcula y rechaza la emisión si no cuadra (422 totals_mismatch, tolerancia 0,01).

201 Created:

{
"id": "6f1e8a24-91cd-4c73-9a1f-2b0f5d7e4c88",
"tipo": "factura",
"pais": "ES",
"estado": "registrado",
"secuencial": "F2026-0001",
"huella": "3C464DAF61ACB827C65FDA19F352A4E3BDC2C640E9E9D2CF5C7BCBFB9A2D62FB",
"huella_anterior": "A1B2…",
"referencia_aeat": null,
"fecha_registro": "2026-09-25T10:31:07+02:00",
"tipo_factura": "F1",
"ambiente": "produccion",
"totales": { "total_sin_impuestos": 100.0, "descuento": 0.0, "iva": 21.0, "importe_total": 121.0 },
"urls": { "detalle": "…", "pdf": "…", "xml": null, "verificacion": "https://…/ValidarQR?…" }
}
CampoQué es
secuencialNúmero completo de la factura (F2026-0001)
huellaSHA-256 del registro, encadenada con la factura anterior. Identifica el comprobante
huella_anteriorLa huella del registro anterior; vacía en la primera factura
tipo_facturaClasificación AEAT: F1 completa, F2 simplificada, F3 sustitutiva, R1/R5 rectificativas
referencia_aeatEl CSV que devuelve la AEAT al aceptar el registro. null hasta entonces
urls.verificacionLa URL del QR: comprueba la factura en la sede de la AEAT
urls.xmlSiempre null: VERI*FACTU no deja un XML descargable
Ventana de terminal
curl -X POST https://olympus.atharix.com/api/v1/invoices/issue \
-H "X-API-Key: $OLYMPUS_API_KEY" \
-H "Idempotency-Key: venta-4821" \
-H "Content-Type: application/json" \
-d '{
"referencia_externa": "SO-2026-0912",
"comprador": {
"identificacion": "B87654321",
"razon_social": "CLIENTE EJEMPLO S.L.",
"email": "facturas@ejemplo.es",
"direccion": "Gran Vía 28, Madrid"
},
"items": [
{
"codigo_principal": "SRV-001",
"descripcion": "Servicio de consultoría",
"cantidad": 10,
"precio_unitario": 60.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_21" }]
},
{
"codigo_principal": "LIB-002",
"descripcion": "Manual técnico",
"cantidad": 1,
"precio_unitario": 30.00,
"impuestos": [{ "codigo_impuesto": "ES_IVA_4" }]
}
],
"retencion": 15,
"totales": { "total_sin_impuestos": 630.00, "importe_total": 757.20 }
}'
ErrorCausa habitual
business_not_readyEl negocio no tiene VERI*FACTU activo
missing_tax_codeUna línea sin IVA, o al 0 % sin decir por qué
field_not_supported_hereEnviaste establecimiento o secuencial, que son de Ecuador
document_rejected_before_issuingLa factura no cumple una regla de VERI*FACTU: comprador extranjero sin país, simplificada por encima del límite, total cero
totals_mismatchRedondeos distintos entre tu sistema y Olympus
external_id_conflictLa venta ya estaba facturada. Recupera la factura con details.id

Todos, con detalle, en Errores.