Skip to main content

Endpoint Description

The /process_excel endpoint accepts an Excel file containing invoice data and transforms each row into a structured JSON document following the Venezuelan electronic invoice standard. The API returns a ZIP file containing all generated invoices organized into batches.

HTTP Method and Path

POST http://localhost:8000/process_excel

Request Parameters

file
file
required
Excel file (.xlsx or .xls) containing invoice data. The file should include columns for customer information, invoice details, amounts, and dates.Expected columns:
  • Correlativo (Invoice number)
  • Fecha Emision (Issue date)
  • Fecha Vencimiento (Due date)
  • Fecha Pago (Payment date)
  • Cliente (Customer name)
  • Documento (Document type)
  • DNI/C.I./C.C./IFE (ID number)
  • Dirección (Address)
  • Telefono (Phone)
  • Correo (Email)
  • Plan (Service description)
  • Total (Total in USD)
  • bolivares (Total in Bolivares)
  • bolivares sin iva (Bolivares without VAT)
  • precio sin iva (USD without VAT)
  • Tasa (Exchange rate)
  • Forma de Pago (Payment method)
  • ID Servicio (Service ID)

Content-Type

multipart/form-data
The request must use multipart/form-data encoding to upload the Excel file.

Request Examples

curl -X POST "http://localhost:8000/process_excel" \
  -H "accept: application/zip" \
  -H "Content-Type: multipart/form-data" \
  -F "[email protected]" \
  -o "invoices_output.zip"

Response Format

Content-Type: application/zip Headers:
Content-Disposition: attachment; filename=FAC-YYYYMMDD.zip
The response is a binary ZIP file stream that can be saved directly to disk.

Response Structure

ZIP File Organization

The returned ZIP file contains a hierarchical structure (main.py:259-271):
FAC-20260304.zip
└── FAC-20260304/
    ├── J408185431-20260304-001/
    │   ├── 0000001.json
    │   ├── 0000002.json
    │   ├── ...
    │   └── 0000100.json
    ├── J408185431-20260304-002/
    │   ├── 0000101.json
    │   ├── ...
    │   └── 0000200.json
    └── J408185431-20260304-003/
        └── ...
  • Date format: YYYYMMDD (e.g., 20260304 for March 4, 2026)
  • Batch folders: Invoices are grouped in batches of 100
  • Batch naming: J408185431-YYYYMMDD-XXX where XXX is the batch number (001, 002, etc.)
  • File naming: Invoice files are named with zero-padded correlative numbers (0000001.json, 0000002.json, etc.)

JSON Invoice Structure

Each JSON file contains a complete electronic invoice document (main.py:94-249):
{
  "DocumentoElectronico": {
    "Encabezado": {
      "IdentificacionDocumento": {
        "TipoDocumento": "01",
        "NumeroDocumento": "123",
        "FechaEmision": "04/03/2026",
        "FechaVencimiento": "04/04/2026",
        "HoraEmision": "10:00:00 am",
        "Anulado": false,
        "TipoDePago": "Inmediato",
        "Serie": "",
        "Sucursal": "002",
        "TipoDeVenta": "Interna",
        "Moneda": "BSD",
        "TransaccionId": "FA123"
      },
      "Comprador": {
        "TipoIdentificacion": "V",
        "NumeroIdentificacion": "12345678",
        "RazonSocial": "Cliente Name",
        "Direccion": "Customer Address",
        "Pais": "VE",
        "Telefono": ["555-1234"],
        "Correo": ["[email protected]"]
      },
      "Totales": {
        "NroItems": "1",
        "MontoGravadoTotal": "1160.00",
        "MontoExentoTotal": "0.00",
        "SubtotalAntesDescuento": "1000.00",
        "Subtotal": "1000.00",
        "TotalIVA": "160.00",
        "MontoTotalConIVA": "1160.00",
        "TotalAPagar": "1160.00",
        "MontoEnLetras": "mil ciento sesenta",
        "ImpuestosSubtotal": [
          {
            "CodigoTotalImp": "G",
            "AlicuotaImp": "16.00",
            "BaseImponibleImp": "1000.00",
            "ValorTotalImp": "160.00"
          }
        ],
        "FormasPago": [
          {
            "Descripcion": "Transferencia",
            "Fecha": "04/03/2026",
            "Forma": "01",
            "Monto": "1160.00",
            "Moneda": "BSD",
            "TipoCambio": "0.00"
          }
        ]
      },
      "TotalesOtraMoneda": {
        "Moneda": "USD",
        "TipoCambio": "50.00",
        "MontoGravadoTotal": "20",
        "Subtotal": "20",
        "TotalAPagar": "23",
        "TotalIVA": "3",
        "MontoTotalConIVA": "23",
        "MontoEnLetras": "veintitrés"
      }
    },
    "DetallesItems": [
      {
        "NumeroLinea": "1",
        "CodigoPLU": "005",
        "IndicadorBienoServicio": "2",
        "Descripcion": "Internet Service Plan",
        "Cantidad": "1",
        "UnidadMedida": "4L",
        "PrecioUnitario": "1000.00",
        "DescuentoMonto": "0.00",
        "PrecioItem": "1000.00",
        "CodigoImpuesto": "G",
        "TasaIVA": "16",
        "ValorIVA": "160.00",
        "ValorTotalItem": "1000.00"
      }
    ],
    "InfoAdicional": [
      {"Campo": "Contrato", "Valor": "SVC-12345"},
      {"Campo": "Mes1", "Valor": "JUL"},
      {"Campo": "Cmes1", "Valor": "3456"},
      {"Campo": "Promedio", "Valor": "3128"}
    ],
    "EsLote": true
  }
}
Key Features:
  • Dual Currency Support: Both Bolivares (BSD) and US Dollars (USD) with automatic exchange rate conversion
  • VAT Calculation: Automatic IVA (16%) calculation on all amounts (main.py:83-84)
  • Amount to Words: Monetary amounts converted to Spanish words (main.py:36-71)
  • Usage Statistics: Random navigation statistics for service tracking (main.py:86-92)
  • Batch Processing: Each invoice marked with "EsLote": true for batch processing
Document Sections:
  1. IdentificacionDocumento: Invoice metadata, dates, and transaction ID
  2. Comprador: Customer information (ID, name, address, contact)
  3. Totales: Financial totals in Bolivares with tax breakdown
  4. TotalesOtraMoneda: Financial totals in USD
  5. DetallesItems: Line items (services/products)
  6. InfoAdicional: Additional service contract and usage data

Status Codes

200
Success
Request processed successfully. Returns a ZIP file containing all generated invoices.
422
Validation Error
Invalid request. The file parameter is missing or the uploaded file is not a valid Excel file.Example Error Response:
{
  "detail": [
    {
      "loc": ["body", "file"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
500
Internal Server Error
Server encountered an error processing the Excel file. This may occur due to:
  • Malformed Excel file structure
  • Missing required columns
  • Invalid data types in cells
  • Memory issues with large files
Example Error Response:
{
  "detail": "Internal server error"
}

Error Responses

Missing File Parameter

{
  "detail": [
    {
      "loc": ["body", "file"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

Invalid File Format

If the uploaded file cannot be parsed as Excel:
{
  "detail": "Error reading Excel file: ..."
}

Missing Required Columns

If the Excel file is missing required columns, pandas will raise a KeyError during processing:
{
  "detail": "KeyError: 'Correlativo'"
}
Ensure your Excel file contains all required columns with exact spelling and capitalization as shown in the parameters section.

Implementation Details

The endpoint implementation (main.py:252-278):
@app.post("/process_excel")
async def process_excel(file: UploadFile = File(...)):
    contents = await file.read()
    df = pd.read_excel(io.BytesIO(contents)).fillna("")

    hoy = datetime.now().strftime("%Y%m%d")

    # Create ZIP in memory
    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, "w") as zf:
        for idx, row in df.iterrows():
            data = transformar_fila(row)
            correlativo = str(row["Correlativo"]).zfill(6)

            lote_num = (idx // 100) + 1
            lote_nombre = f"J408185431-{hoy}-{str(lote_num).zfill(3)}"
            folder = f"FAC-{hoy}/{lote_nombre}/"

            filename = f"{folder}0{correlativo}.json"
            zf.writestr(filename, json.dumps(data, indent=4, ensure_ascii=False))

    zip_buffer.seek(0)
    return StreamingResponse(
        zip_buffer,
        media_type="application/zip",
        headers={"Content-Disposition": f"attachment; filename=FAC-{hoy}.zip"}
    )

Processing Flow

  1. File Upload: Receives Excel file via multipart/form-data (line 253)
  2. Parse Excel: Reads file into pandas DataFrame, fills NA values with empty strings (line 255)
  3. Generate Date: Creates timestamp for folder naming (line 257)
  4. Create ZIP: Initializes in-memory ZIP archive (line 260)
  5. Process Rows: Iterates through each Excel row (line 262)
    • Transforms row data into JSON structure via transformar_fila()
    • Zero-pads correlative number to 6 digits
    • Calculates batch number (100 invoices per batch)
    • Generates folder and file paths
    • Writes JSON to ZIP archive
  6. Return Response: Streams ZIP file to client with appropriate headers (line 274-278)
The entire ZIP file is generated in memory using io.BytesIO(), making it efficient for moderate file sizes but potentially memory-intensive for very large datasets.

Performance Considerations

  • Batch Size: Invoices are automatically split into batches of 100 to maintain organized folder structures
  • Memory Usage: The entire ZIP file is built in memory. For very large Excel files (>10,000 rows), consider monitoring memory usage
  • Processing Time: Scales linearly with the number of rows in the Excel file
  • File Size: Generated JSON files are formatted with 4-space indentation, which increases readability but also file size
For optimal performance, keep individual Excel files under 5,000 rows. Larger datasets can be split into multiple files and processed separately.

API Overview

View complete API documentation

Error Handling

Learn about error codes and responses

Build docs developers (and LLMs) love