Skip to content

Invoices

POST /v1/invoices issues an invoice (factura, XML 2.1.0): the document that supports a sale of goods or services. The buyer can be identified or a final consumer.

Terminal window
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
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 }
}
Field Required Notes
customer Yes The buyer: idType, id, name, and optionally address and email. The email is where Flashpi sends the RIDE and the XML.
items Yes 1 to 1000 lines.
items[].code Yes Your product code, up to 25 characters. auxiliaryCode is an optional second code, such as the barcode.
items[].description Yes Up to 300 characters.
items[].unit No Unit of measure, such as UNIT, LITER or KILOGRAM.
items[].quantity, items[].unitPrice Yes Decimal strings with up to 6 decimals. The unit price excludes taxes.
items[].discount No The discount amount of the line (not a percentage), up to 2 decimals. It cannot exceed quantity × unit price.
items[].taxes Yes Exactly one VAT, and optionally one ad valorem ICE. See Taxes.
items[].additionalDetails No Up to 3 extra details printed with the line, name to value.
payments Yes 1 to 50 payments that add up to the total, each with method, amount and an optional term and termUnit.
tip No The tip (propina), up to 2 decimals. Defaults to 0.
waybillNumber No The number of the waybill that carried the goods (001-001-000000045).
expectedTotal No Your own total; a different computed total is refused with 422 total_mismatch.

The fields every request shares (issuerId, establishment, emissionPoint, issueDate, sequential, additionalInfo, options) work as everywhere.

For the request above:

Line Quantity × price − discount Subtotal VAT
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 %

The VAT is computed per rate on the summed base: 15 % of 57.50 is 8.625, rounded half up to 8.63. The total is the subtotal (60.31) plus the taxes (8.63) plus the tip (0.00): 68.94, which matches the payment and the expectedTotal.

202 Accepted, with 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"
}

With options.waitForAuthorization, the answer is 200 OK with the document authorized, rejected or failed when the SRI answers within the wait (see Sync and async modes). The invoice.authorized and invoice.rejected webhooks report the SRI’s decision.

  • VAT (vat): every line has exactly one. The rates are 0, 5, 8 (the differentiated tourism rate, on the days a decree sets), 12, 13, 14, 15, exempt (exento) and not_subject (no objeto de impuesto). Use the rate in force on the issue date: the SRI rejects a document with a wrong one. Flashpi does not know yet when every rate started or ended, so it only refuses with not_in_force the rates it knows were not in force.
  • ICE (ice): one optional ad valorem ICE per line, with its 4-digit code of the SRI’s TABLA 18 and its percentage. The ICE is part of the VAT base. Specific ICE (an amount per unit) is not supported yet.

A line of 10 × 1.00 with "taxes": [{ "type": "ice", "code": "3031", "rate": "75" }, { "type": "vat", "rate": "15" }] gets an ICE of 7.50 and a VAT of 15 % on 17.50 (2.63), for a total of 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" }
]

For a buyer who does not identify themselves, send only the identification type. Flashpi writes the final consumer identification (9999999999999) and prints 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" }]
}

The document’s counterparty is then { "id": "9999999999999", "name": "CONSUMIDOR FINAL" }, and without an email email.status is skipped.

Answer When
422 validation_failed A field is missing or invalid; errors[] lists every one (for example items[0].code required, customer.id invalid_check_digit, payments amount_mismatch).
422 total_mismatch expectedTotal differs from the computed total; the body has both.
409 sequential_already_used The sequential you chose is taken in that series.
409 sequentials_exhausted The series reached sequential 999,999,999.
403 key_scope_mismatch, key_read_only The key cannot issue for this issuer.

See Errors for the format and every code.