Skip to content
pdfconversionapi

ODS to JSON API

POST an .ods file to /v2/convert/ods/to/json and get one sheet back as a JSON array: one object per row, keyed by the first row. The sample's Plots sheet becomes 14 objects in 2,877 bytes.

Endpoint
POST /v2/convert/ods/to/json
Accepts
ods
Sample timing
under 1 ms median of 5 runsHow we measure
Request size
Up to 10 MB on the Free plan or 100 MB on paid plans, all files together

Request and response

Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.

curl -sS -X POST \
  https://api.pdfconversionapi.com/v2/convert/ods/to/json \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@garden-plots-2026.ods \
  -o response.json

# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
  mkdir -p converted
  name=$(jq -r '.Files[0].FileName' response.json)
  jq -r '.Files[0].FileData' response.json \
    | base64 --decode > "converted/$name"
else
  cat response.json
fi
200 OKunder 1 ms median1 file, 2.8 KB
{
  "ConversionCost": 1,
  "ConversionTime": 0,
  "Files": [
    {
      "FileName": "garden-plots-2026.json",
      "FileExt": "json",
      "FileSize": 2877,
      "FileData": "WwogIHsKICAgICJBbm51YWwg…"
    }
  ]
}

Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.

The sample, converted

The same file the code sends. Download the input and the output and compare them yourself.

garden-plots-2026.json, first 30 of 142 lines

[  {    "Annual fee": 75.0,    "Area (sq ft)": 48.0,    "Bed type": "Raised",    "Notes": null,    "Paid": 1.0,    "Plot": "A-01",    "Since": "2021-03-14",    "Water tap": true  },  {    "Annual fee": 75.0,    "Area (sq ft)": 48.0,    "Bed type": "Raised",    "Notes": null,    "Paid": 1.0,    "Plot": "A-02",    "Since": "2022-04-02",    "Water tap": true  },  {    "Annual fee": 55.0,    "Area (sq ft)": 32.0,    "Bed type": "Raised",    "Notes": "Second half due June 1",    "Paid": 0.5,    "Plot": "A-03",    "Since": "2024-05-19",    "Water tap": true
Input
garden-plots-2026.ods (30 KB)
Output
garden-plots-2026.json (2.8 KB)
Source
Written for this site: a fictional community garden's plot register and harvest chart in three sheets, one of them hidden, saved as an OpenDocument spreadsheet (CC0-1.0). How it was made
Made by
2026-11-04, API build 9eeeb0640aba

Parameters

Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.

ParameterWhat it does
WorksheetNamestringThe sheet to read, matched without regard to case. WorksheetName=Harvest returns the six monthly rows with their Total (lb) values.
WorksheetIndexinteger, default 1The sheet by position, hidden sheets included: 3 reads the sample's hidden Fees sheet, and 4 returns 400 "WorksheetIndex is 4, but the workbook has 3 worksheets".Values: 1 to the number of sheets
FirstRowIsHeaderboolean, default trueWith false, every row comes back as an array of values, and the header row is the first array.
FileNamestringName of the JSON file, without .json.
StoreFileboolean, default falseAnswer with a link that lasts 3 hours instead of the file contents.

Not supported yet

Setting one of these to anything but its default returns 400.

OptionWhat to do instead
ActiveWorksheetOnlytrue returns 400 for ODS files; name the sheet with WorksheetName instead.

What carries over, and what doesn't

Kept

  • Value types: 48 sq ft as 48.0, TRUE as true, the 75% paid share as 0.75, and the $75.00 fee as 75.0
  • Formula results as saved in the file: Annual fee values and the Total row (1108.0 sq ft, 1505.0 dollars)
  • Dates as text in ISO form ("2021-03-14"); a cell with a time gives "2026-10-31 14:30:00"
  • Empty cells as null, including Since for the open plot A-04
  • Text with commas and quotes, escaped for JSON (Bee hotel on the \"north\" fence)

Lost or not yet supported

  • Column order. Keys come out sorted alphabetically (Annual fee, Area (sq ft), Bed type, ...), not left to right.
  • Formatting: $, % and date formats are dropped and the raw values stay.
  • Blank rows are not skipped. The empty line above the sample's Total row becomes an object with every value null.
  • Duplicate headers: when two columns share a name, only the right-hand column's value is kept.
  • Formula errors such as #DIV/0! come out as an empty string.
  • Other sheets and the chart. One sheet per request, values only.

Limits

  • One ODS per request, one sheet per response.
  • Password-protected ODS files can't be read yet: without Password the answer is 422 "the input file is password-protected", with it 400. The ODS to image routes do open them.
  • Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
  • 120 seconds per conversion, then 504.

Where teams use it

Spreadsheets kept by volunteers, read by a website

A club or garden keeps its register in an office suite. Convert the saved .ods to JSON on each upload and render the list on the site, without asking anyone to learn a database.

Importing records into a database

Each object maps to a row: true/false, numbers and empty cells arrive as JSON booleans, numbers and null, ready for an insert.

Reading lookup tables from a hidden sheet

Rates and settings sometimes live on a hidden sheet. WorksheetIndex reaches it; the sample's hidden Fees sheet comes back as two objects.

Questions

Why are the keys in a different order than my columns?

The objects are written with their keys sorted alphabetically. Values are not lost, only reordered. If you need column order, send FirstRowIsHeader=false: each row then comes back as an array in left-to-right order, with the header names in the first array.

My table doesn't start in A1. Does that matter?

No. Reading starts at the first filled cell: in a test sheet with two empty rows and an empty first column, the header row and data were found and the empty column was left out.

Are formulas recalculated?

No, the result saved in the file is used. Files saved by an office suite carry those results. A workbook written by a script without saved results gives null for those cells: in our test, an XLSX copy of the sample sent to this route returned null for every Annual fee.

What happens with headers that are empty or repeated?

An empty header cell gets a generated key: the second column becomes "column2". Repeated names collide, and the later column overwrites the earlier one, so rename them before converting.

Convert your first ODS file in a minute.