Saltearse al contenido

Facturar en Ecuador

Emitir una factura

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

El payload mínimo es corto: un comprador y una línea. Todo lo demás tiene un valor por defecto sensato.

{
"comprador": {
"identificacion": "1792060346001",
"razon_social": "COMERCIAL ANDINA S.A."
},
"items": [
{ "descripcion": "Servicio de soporte", "cantidad": 1, "precio_unitario": 100.00 }
]
}

Eso emite una factura con IVA 0 %, con fecha de hoy y el secuencial que toque. En la práctica querrás enviar algo más.

CampoObligatorioPor defectoNotas
comprador✅—Ver más abajo
items✅—Al menos una línea
referencia_externa——Envíala siempre. Tu identificador de la venta
fecha_emision—Hoy en EcuadorYYYY-MM-DD. No puede ser futura
fecha_vencimiento——Para ventas a crédito
establecimiento—El de la clave o el del negocio{ "codigo", "punto_emision" }
secuencial—El siguiente de la serieSolo si controlas la numeración
totales——Si lo envías, se comprueba
moneda—USDEl SRI solo admite dólares
info_adicional—[]Campos libres que salen en el RIDE
campos_personalizados—{}Valores de los campos personalizados del negocio por su clave ({"orden_compra": "OC-7781"}). Los marcados «mostrar en el documento» van al RIDE y al infoAdicional del XML
enviar_email—trueEnviar el RIDE al comprador al autorizarse
notas——Texto libre interno
{
"tipo_identificacion": "04",
"identificacion": "1792060346001",
"razon_social": "COMERCIAL ANDINA S.A.",
"email": "facturas@andina.ec",
"telefono": "0991234567",
"direccion": "Av. Amazonas N24-03, Quito"
}
CampoObligatorioNotas
identificacion✅RUC, cédula, pasaporte…
razon_social✅Nombre legal del comprador
tipo_identificacion—Se deduce del formato si no lo envías
email—Necesario si quieres que el RIDE llegue por correo
telefono, direccion—Salen en el RIDE

Tipos de identificación del SRI:

CódigoTipo
04RUC (13 dígitos)
05Cédula (10 dígitos)
06Pasaporte
07Consumidor final
08Identificación del exterior
09Placa

Para ventas sin datos del cliente, ver Consumidor final.

Si la identificación no corresponde a ningún cliente del negocio, Olympus crea el contacto automáticamente con los datos que enviaste. Así el negocio ve a sus clientes en Olympus aunque facture solo desde tu sistema.

Si prefieres que no, desactiva “Crear clientes automáticamente” en la 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": "2", "codigo_porcentaje": "4" }]
}
CampoObligatorioNotas
descripcion✅Lo que ve el cliente en el RIDE
cantidad✅Mayor que cero
precio_unitario✅Sin impuestos, dos decimales
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
impuestos—Sin este campo, la línea va con IVA 0 %

El cálculo de cada línea es:

subtotal = cantidad × precio_unitario − descuento
IVA = subtotal × tarifa

Si codigo_principal coincide con el SKU de un producto de Olympus, la línea queda enlazada. Eso tiene una consecuencia importante: si el producto es un bien, la venta descuenta stock, y si no hay existencias la emisión falla con 422 insufficient_stock.

Si no quieres tocar inventario, usa un código que no exista como SKU o deja codigo_principal vacío.

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

Es opcional pero muy recomendable. Si lo envías, Olympus compara con lo que calcula y rechaza la emisión si no cuadra (422 totals_mismatch, tolerancia 0,01).

Sirve para que nunca se emita un comprobante distinto del que tu sistema contabilizó: si vuestros redondeos difieren, te enteras antes de que el SRI lo autorice, no después.

202 Accepted:

{
"id": "6f1e8a24-91cd-4c73-9a1f-2b0f5d7e4c88",
"tipo": "factura",
"estado": "pendiente",
"clave_acceso": "2409202601179001234500110010010000000011234567813",
"secuencial": "001-001-000000001",
"ambiente": "produccion",
"fecha_emision": "2026-09-24",
"referencia_externa": "SO-2026-0912",
"totales": { "total_sin_impuestos": 100.0, "descuento": 0.0, "iva": 15.0, "importe_total": 115.0 },
"urls": { "detalle": "…", "pdf": null, "xml": null, "publica": null }
}

Guarda el id y la clave_acceso. El id es tu referencia para consultar, descargar y reenviar; la clave de acceso es el identificador del comprobante ante el SRI, y es lo que tu cliente usará para verificarlo.

Los enlaces de pdf, xml y publica llegan vacíos hasta que el SRI autorice.

El SRI suele tardar segundos. Consulta el estado con GET /invoices/{id} o espera el webhook (próximamente). Ver Estados de un comprobante.

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",
"establecimiento": { "codigo": "001", "punto_emision": "001" },
"comprador": {
"tipo_identificacion": "04",
"identificacion": "1792060346001",
"razon_social": "COMERCIAL ANDINA S.A.",
"email": "facturas@andina.ec",
"direccion": "Av. Amazonas N24-03, Quito"
},
"items": [
{
"codigo_principal": "SRV-001",
"descripcion": "Servicio de soporte mensual",
"cantidad": 1,
"precio_unitario": 100.00,
"impuestos": [{ "codigo": "2", "codigo_porcentaje": "4" }]
},
{
"codigo_principal": "LIC-010",
"descripcion": "Licencia adicional",
"cantidad": 2,
"precio_unitario": 25.00,
"descuento": 5.00,
"impuestos": [{ "codigo": "2", "codigo_porcentaje": "4" }]
}
],
"totales": { "total_sin_impuestos": 145.00, "descuento": 5.00, "importe_total": 166.75 },
"info_adicional": [{ "nombre": "Orden de compra", "valor": "OC-7781" }]
}'
ErrorCausa habitual
totals_mismatchRedondeos distintos entre tu sistema y Olympus. Revisa línea a línea
external_id_conflictLa venta ya estaba facturada. Recupera la factura con details.id
business_not_readyEl negocio no tiene la firma electrónica configurada
insufficient_stockUna línea enlaza un producto sin existencias
establishment_not_foundEl código de establecimiento no existe. Consulta GET /establishments
validation_errorFalta un campo o tiene un valor inválido; details dice cuál

Todos, con detalle, en Errores.