Facturas
POST /v1/invoices emite una factura (XML 2.1.0): el comprobante que respalda una venta de bienes o servicios. El comprador puede estar identificado o ser consumidor final.
Solicitud
Sección titulada «Solicitud»curl https://api.flashpi.com.ec/v1/invoices \ -H "Authorization: Bearer $FLASHPI_API_KEY" \ -H "Idempotency-Key: order-PO-4812" \ -H "Content-Type: application/json" \ -d @invoice.json{ "issuerId": "01a0fd6a-d098-76ca-b492-1bcb6505a7bd", "establishment": "001", "emissionPoint": "001", "issueDate": "2026-10-15", "customer": { "idType": "ruc", "id": "1790000000001", "name": "Supermercados La Pradera S.A.", "email": "compras@example.com", "address": "Av. Amazonas N34-12, Quito" }, "items": [ { "code": "CAF-500", "auxiliaryCode": "2001234500012", "description": "Ground coffee 500 g", "quantity": "3", "unitPrice": "4.25", "discount": "0.75", "taxes": [{ "type": "vat", "rate": "15" }], "additionalDetails": { "Batch": "L-2026-10" } }, { "code": "SRV-INST", "description": "Espresso machine installation", "quantity": "1", "unitPrice": "45.50", "taxes": [{ "type": "vat", "rate": "15" }] }, { "code": "LEC-1L", "description": "Whole milk 1 L", "unit": "LITER", "quantity": "2.5", "unitPrice": "1.123456", "taxes": [{ "type": "vat", "rate": "0" }] } ], "payments": [{ "method": "credit_card", "amount": "68.94", "term": "3", "termUnit": "months" }], "additionalInfo": { "Order": "PO-4812" }, "expectedTotal": "68.94", "options": { "sendEmail": true }}| Campo | Obligatorio | Notas |
|---|---|---|
customer |
Sí | El comprador: idType, id, name y, opcionalmente, address y email. El correo es donde Flashpi envía el RIDE y el XML. |
items |
Sí | De 1 a 1000 líneas. |
items[].code |
Sí | Tu código de producto, de hasta 25 caracteres. auxiliaryCode es un segundo código opcional, como el código de barras. |
items[].description |
Sí | Hasta 300 caracteres. |
items[].unit |
No | La unidad de medida, como UNIT, LITER o KILOGRAM. |
items[].quantity, items[].unitPrice |
Sí | Cadenas decimales de hasta 6 decimales. El precio unitario no incluye impuestos. |
items[].discount |
No | El valor del descuento de la línea (no un porcentaje), con hasta 2 decimales. No puede superar cantidad × precio unitario. |
items[].taxes |
Sí | Exactamente un IVA y, opcionalmente, un ICE ad valorem. Consulta Impuestos. |
items[].additionalDetails |
No | Hasta 3 detalles adicionales impresos con la línea, nombre y valor. |
payments |
Sí | De 1 a 50 pagos que suman el total, cada uno con method, amount y, opcionalmente, term y termUnit. |
tip |
No | La propina, con hasta 2 decimales. Por defecto 0. |
waybillNumber |
No | El número de la guía de remisión que transportó la mercadería (001-001-000000045). |
expectedTotal |
No | Tu propio total; si el total calculado es distinto, se rechaza con 422 total_mismatch. |
Los campos que comparten todas las solicitudes (issuerId, establishment, emissionPoint, issueDate, sequential, additionalInfo, options) funcionan igual que en todos los comprobantes.
Lo que calcula Flashpi
Sección titulada «Lo que calcula Flashpi»Para la solicitud anterior:
| Línea | Cantidad × precio − descuento | Subtotal | IVA |
|---|---|---|---|
| Ground coffee 500 g | 3 × 4.25 − 0.75 | 12.00 | 15 % |
| Espresso machine installation | 1 × 45.50 | 45.50 | 15 % |
| Whole milk 1 L | 2.5 × 1.123456 = 2.80864 | 2.81 | 0 % |
El IVA se calcula por tarifa sobre la base sumada: el 15 % de 57.50 es 8.625, que se redondea mitad hacia arriba a 8.63. El total es el subtotal (60.31) más los impuestos (8.63) más la propina (0.00): 68.94, que coincide con el pago y con expectedTotal.
Respuesta
Sección titulada «Respuesta»202 Accepted, con Location: /v1/documents/01a1412b-ae38-7c39-8c71-16d2b5dfc472:
{ "id": "01a1412b-ae38-7c39-8c71-16d2b5dfc472", "type": "invoice", "environment": "test", "status": "processing", "issuerId": "01a0fd6a-d098-76ca-b492-1bcb6505a7bd", "establishment": "001", "emissionPoint": "001", "sequential": 123, "number": "001-001-000000123", "accessKey": "1510202601179000000000110010010000001239052713811", "issueDate": "2026-10-15", "xmlVersion": "2.1.0", "counterparty": { "id": "1790000000001", "name": "Supermercados La Pradera S.A." }, "totals": { "subtotal": "60.31", "discount": "0.75", "taxes": [ { "type": "vat", "rate": "15", "taxableBase": "57.50", "amount": "8.63" }, { "type": "vat", "rate": "0", "taxableBase": "2.81", "amount": "0.00" } ], "tip": "0.00", "total": "68.94" }, "authorization": { "number": null, "authorizedAt": null }, "ride": { "status": "pending", "template": null, "generatedAt": null }, "email": { "requested": true, "status": "queued", "deliveries": [], "warnings": [] }, "sriMessages": [], "failure": null, "voidedAt": null, "createdAt": "2026-10-15T20:05:44.120Z", "updatedAt": "2026-10-15T20:05:44.120Z"}Con options.waitForAuthorization, la respuesta es 200 OK con el comprobante authorized, rejected o failed cuando el SRI responde dentro de la espera (consulta Modo síncrono y asíncrono). Los webhooks invoice.authorized e invoice.rejected informan la decisión del SRI.
Impuestos
Sección titulada «Impuestos»- IVA (
vat): cada línea tiene exactamente uno. Las tarifas son0,5,8(la tarifa diferenciada de turismo, en los días que fija un decreto),12,13,14,15,exempt(exento) ynot_subject(no objeto de impuesto). Usa la tarifa vigente en la fecha de emisión: el SRI rechaza un comprobante con una tarifa equivocada. Flashpi todavía no sabe cuándo empezó o terminó cada tarifa, así que solo rechaza connot_in_forcelas tarifas que sabe que no estaban vigentes. - ICE (
ice): un ICE ad valorem opcional por línea, con su código de 4 dígitos de la TABLA 18 del SRI y su porcentaje. El ICE forma parte de la base del IVA. El ICE específico (un valor por unidad) todavía no está disponible.
Una línea de 10 × 1.00 con "taxes": [{ "type": "ice", "code": "3031", "rate": "75" }, { "type": "vat", "rate": "15" }] tiene un ICE de 7.50 y un IVA del 15 % sobre 17.50 (2.63), con un total de 20.13:
"taxes": [ { "type": "ice", "code": "3031", "rate": "75", "taxableBase": "10.00", "amount": "7.50" }, { "type": "vat", "rate": "15", "taxableBase": "17.50", "amount": "2.63" }]Consumidor final
Sección titulada «Consumidor final»Para un comprador que no se identifica, envía solo el tipo de identificación. Flashpi escribe la identificación de consumidor final (9999999999999) e imprime CONSUMIDOR FINAL:
{ "issuerId": "01a0fd6a-d098-76ca-b492-1bcb6505a7bd", "establishment": "001", "emissionPoint": "001", "customer": { "idType": "final_consumer" }, "items": [ { "code": "CAF-500", "description": "Ground coffee 500 g", "quantity": "1", "unitPrice": "4.25", "taxes": [{ "type": "vat", "rate": "15" }] } ], "payments": [{ "method": "cash", "amount": "4.89" }]}El counterparty del comprobante es entonces { "id": "9999999999999", "name": "CONSUMIDOR FINAL" } y, sin correo, email.status es skipped.
Errores
Sección titulada «Errores»| Respuesta | Cuándo |
|---|---|
422 validation_failed |
Falta un campo o no es válido; errors[] los lista todos (por ejemplo items[0].code required, customer.id invalid_check_digit, payments amount_mismatch). |
422 total_mismatch |
expectedTotal es distinto del total calculado; el cuerpo trae ambos. |
409 sequential_already_used |
El sequential que elegiste ya está usado en esa serie. |
409 sequentials_exhausted |
La serie llegó al secuencial 999.999.999. |
403 key_scope_mismatch, key_read_only |
La llave no puede emitir para este emisor. |
Consulta Errores para ver el formato y todos los códigos.