Convert Excel (XLSX) to Markdown tables
Convert Excel spreadsheets to Markdown tables with the Mdkit API — a table an LLM can actually read, without cell-by-cell parsing code.
Last updated
| Output shape | One '## sheet name' heading plus one Markdown table per sheet |
|---|---|
| Accepted format | .xlsx only (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) |
Spreadsheets convert to Markdown tables — the representation LLMs handle
far better than raw XML or a CSV blob whose headers went missing. Upload the
.xlsx to POST /v1/convert like any other document: the synchronous lane
walks the workbook sheet by sheet and emits, for each one, a ## <sheet name>
heading followed by a single Markdown table. No cell-by-cell parsing code, no
spreadsheet library in your own service, and no format parameter — the endpoint
takes the type from the upload.
curl
curl -F "file=@figures.xlsx;type=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" \
https://api.mdkit.online/v1/convert
The markdown field comes back looking like this:
## Q3
| Region | Revenue | Growth |
| --- | --- | --- |
| EMEA | 412000 | 0.08 |
| APAC | 260500 | 0.13 |
## Q4
| Region | Revenue | Growth |
| --- | --- | --- |
| EMEA | 448900 | 0.09 |
Python — index each sheet on its own
import httpx
XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
with open("figures.xlsx", "rb") as fh:
resp = httpx.post(
"https://api.mdkit.online/v1/convert",
files={"file": ("figures.xlsx", fh, XLSX)},
headers={"X-API-Key": "YOUR_KEY"}, # optional — raises the rate limit
timeout=60,
)
resp.raise_for_status()
markdown = resp.json()["markdown"]
# Every sheet is a "## <name>" section — split it back apart so each sheet can
# be embedded and cited on its own instead of as one giant blob.
sheets: dict[str, str] = {}
for block in markdown.split("\n## "):
name, _, table = block.lstrip("# ").partition("\n")
sheets[name.strip()] = table.strip()
for name, table in sheets.items():
print(name, "→", table.count("\n") + 1, "rows")
Watch the header row
The first row of each sheet becomes the table header. That is right for
a clean data sheet and wrong for a formatted report: if the real header sits on
row 3 under a title and a blank line, the title becomes the header and the real
header lands in the first data row. Either trim the preamble before uploading,
or send the workbook through the
async lane and read the format=json output,
which gives you table cells with their row/column positions instead of a
flattened Markdown grid. Merged cells and stacked multi-row headers flatten the
same way in the fast lane.
Limits
- Cell values are converted, not the spreadsheet: formula results come out as the file stored them, and charts, images, conditional formatting and styling are dropped. The output is the data.
- Sync uploads are capped at 8 MB — a workbook past that belongs on the async lane (50 MB).
- Anonymous calls run at 30 requests per minute per IP; an
X-API-Keyheader raises the limit. Each synchronous conversion costs 1 credit.
Try it
Upload a workbook to the free converter — no signup, up to 4 MB, same conversion as the API.
FAQ
- How do I turn a spreadsheet into a Markdown table?
- POST the .xlsx to /v1/convert and the sheets come back as Markdown tables — the pipe-delimited form models understand well in a prompt.
- Are formulas converted or evaluated?
- You get the cell values as the file stores them, not a recalculated spreadsheet. Mdkit is a conversion API, not a spreadsheet engine.
- What happens with multiple sheets?
- The workbook is converted as a whole: every sheet becomes a '## sheet name' heading followed by its own Markdown table, in workbook order. For very large workbooks, use the async lane — its 50 MB cap is far above the 8 MB synchronous limit.
- Does Mdkit accept the legacy .xls format?
- No — only .xlsx. A legacy .xls upload is rejected with 415, so re-save it as .xlsx (or export it from Excel, LibreOffice or Google Sheets) before uploading.