XLSX Inspector API

September 12, 2026 · View on GitHub

Live instance: https://api.lifestep.io — try /health, and see /openapi.json for the full spec. Free, no signup.

Self-host it: docker compose up -d (see below). MIT licensed.

The checks this API automates are written up as The Spreadsheet Structural Preflight Guide. This service stays free.

Live: https://api.lifestep.io — try GET /health, POST /inspect, GET /openapi.json, docs at /docs.

A stateless FastAPI service for inspecting the structure of .xlsx and .xlsm workbooks before ingestion. It never launches Excel, recalculates formulas, or executes VBA. Workbook parsing uses only Python's standard-library zipfile and xml.etree.ElementTree modules.

What it reports

  • Workbook byte size and OOXML uncompressed size
  • Sheet count, names, and visibility (visible, hidden, or veryHidden)
  • Per-sheet and total formula, cached error-cell, and merged-range counts
  • Presence of external-link package parts
  • Presence of xl/vbaProject.bin
  • Shared-string table entry count
  • Defined-name count
  • Workbook calculation settings

Uploads are limited to 15 MiB. ZIP entry count, expanded size, XML member size, encrypted entries, ambiguous duplicates, and unsafe paths are also bounded or rejected. The service is stateless and does not require API keys, so RapidAPI can apply authentication, quotas, and rate limits at its gateway.

Run locally

python3.12 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

Or with Docker Compose:

docker compose up --build

The Compose endpoint is http://127.0.0.1:8083; interactive docs are at /docs and the RapidAPI-importable specification is at /openapi.json.

Request examples

Multipart upload:

curl --fail-with-body http://127.0.0.1:8083/inspect \
  -F 'file=@report.xlsx'

Raw body:

curl --fail-with-body http://127.0.0.1:8083/inspect \
  -H 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' \
  -H 'X-Filename: report.xlsx' \
  --data-binary '@report.xlsx'

Response schema

{
  "filename": "report.xlsm",
  "total_size_bytes": 48321,
  "uncompressed_size_bytes": 192840,
  "sheet_count": 2,
  "sheet_names": ["Data", "Hidden Calc"],
  "sheets": [
    {
      "name": "Data",
      "state": "visible",
      "formula_count": 14,
      "cached_error_cells_count": 1,
      "merged_range_count": 3
    }
  ],
  "totals": {
    "formula_count": 14,
    "cached_error_cells_count": 1,
    "merged_range_count": 3
  },
  "has_external_links": true,
  "has_vba_project": true,
  "shared_strings_count": 128,
  "defined_names_count": 4,
  "calculation_settings": {
    "calculation_id": 191029,
    "mode": "auto",
    "full_calculation_on_load": true,
    "force_full_calculation": false,
    "calculate_on_save": true
  }
}

filename is null for a raw-body request unless X-Filename is supplied. Missing calculation properties are omitted; if the workbook has no calcPr, the object is empty.

Honest limits

  • This is structural inspection, not a malware verdict or file-safety guarantee.
  • Formula text and counts are read, but formulas are never evaluated or recalculated. Cached values may be stale.
  • VBA is not executed or analyzed; only xl/vbaProject.bin presence is reported.
  • External links are reported by OOXML package-part presence; targets are not fetched or validated.
  • Password-encrypted packages and legacy binary .xls files are not supported.
  • The service does not validate every rule in the full OOXML specification.

Tests

.venv/bin/pip install -r requirements-dev.txt
.venv/bin/pytest -q
.venv/bin/python -c 'import app.main; print(app.main.app.title)'

The paid guide collection is available at lifestep1.gumroad.com.