# Decant: documents into data

> Turn a spreadsheet or PDF into JSON. Files in. Rows out.

Decant converts a CSV or XLSX file into JSON rows under each sheet's header row, or a text PDF into its text page by page, from an upload of up to 5 MB or a public link, without storing the file; it reads one public web page into its title, headings, readable text, links and JSON-LD, honouring robots.txt; and it takes specifications for datasets to buy or license. Conversion and page reading are free within a daily allowance.

Decant. Operated by Tempered Technologies LLC, 8 The Green STE B, Dover, DE 19901. Privacy questions and deletion requests: privacy@forevenza.com. Privacy notice: https://decant.forevenza.com/privacy/

## Offerings

- [Spreadsheet and PDF to JSON](https://decant.forevenza.com/document-conversion/) (https://decant.forevenza.com/document-conversion/index.md): CSV, XLSX or a text PDF, from an upload or a link, as rows or page text.
- [Page to structure](https://decant.forevenza.com/web-extraction/) (https://decant.forevenza.com/web-extraction/index.md): One public page as title, headings, text, links and JSON-LD, robots.txt honoured.
- [Datasets to license](https://decant.forevenza.com/dataset-licensing/) (https://decant.forevenza.com/dataset-licensing/index.md): The data you need to buy or license: domain, fields, coverage, history and refresh.

## Convert a file: POST https://decant.forevenza.com/document-conversion/op/convert

Send the file itself as the request body with its content type, or JSON `{"url": "https://..."}` for a public link. Free within a daily allowance.

- `text/csv`: CSV (tab- or semicolon-separated text is detected from the first line)
- `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`: XLSX
- `application/pdf`: a PDF with a text layer
- `sheet` (query parameter, or a key beside `url`): only this sheet

Cells: a CSV cell becomes a number only when nothing is lost by it (a code with a leading zero such as 0012, or more than 15 digits, stays text); an XLSX cell is the value the file stores; an empty CSV cell comes back as `""`. There are no parse options. To take numbers as text or empty cells as null, shape the answer after the call, for example:

```sh
curl -s -X POST 'https://decant.forevenza.com/document-conversion/op/convert' -H 'content-type: text/csv' --data-binary @prices.csv | jq '.sheets[].rows[] |= map_values(if type == "number" then tostring else . end | if type == "string" and test("^\\s*$") then null else . end)'
```

```sh
curl -s -X POST 'https://decant.forevenza.com/document-conversion/op/convert' \
  -H 'content-type: text/csv' \
  --data-binary @'prices.csv'
```

Worked example: `prices.csv` with header sku, description, unit_price and three rows returns (example · csv · 1 sheet · 3 rows · not truncated · not stored):

```json
{
  "type": "csv",
  "sheets": [
    {
      "name": "csv",
      "header": [
        "sku",
        "description",
        "unit_price"
      ],
      "rows": [
        {
          "sku": "A-100",
          "description": "Hex bolt M8",
          "unit_price": 0.12
        },
        {
          "sku": "A-101",
          "description": "Hex bolt M10",
          "unit_price": 0.18
        },
        {
          "sku": "A-110",
          "description": "Flat washer M8",
          "unit_price": 0.03
        }
      ],
      "row_count": 3,
      "truncated": false
    }
  ]
}
```

Answer shape: spreadsheets give `{ type, sheets: [{ name, header, rows, row_count, truncated }] }`, one object per row keyed by the header row; PDFs give `{ type: "pdf", page_count, pages: [{ page, text }] }`, with a `note` when no page has text. The operation's own example:

```json
{
  "type": "xlsx",
  "sheets": [
    {
      "name": "Prices",
      "header": [
        "sku",
        "description",
        "unit_price"
      ],
      "rows": [
        {
          "sku": "A-100",
          "description": "Hex bolt M8",
          "unit_price": 0.12
        }
      ],
      "row_count": 1,
      "truncated": false
    }
  ]
}
```

## Limits

- 5 MB per file; up to 20,000 rows returned per sheet.
- PDF tables are returned as page text, not as cell grids.
- No OCR: a scanned PDF returns no text and says so.
- The file is processed in memory and not stored.
- XLSX is read as Office Open XML (ECMA-376): https://ecma-international.org/publications-and-standards/standards/ecma-376/

## Something conversion does not cover

POST JSON to https://decant.forevenza.com/document-conversion/requests?via=decant-home with { action, need, specifications, requested_fields, contact }. specifications takes only file_type (xlsx, csv, pdf, docx, image, other), target_fields, files and pages_per_file; anything else (ocr_text, line_items) goes in requested_fields or need. You get a reference number; a requirement is not an order and nothing is charged.

```json
{
  "action": "convert",
  "need": "Turn our distributor's XLSX price list into JSON rows so we can compare unit prices.",
  "specifications": {
    "file_type": "xlsx",
    "target_fields": [
      "sku",
      "description",
      "unit_price"
    ]
  }
}
```

Schema: https://decant.forevenza.com/document-conversion/schema.json

What happens: You send the file (up to 5 MB) or a public link to it. CSV and XLSX become one JSON object per row under each sheet's header row; a PDF with a text layer becomes its text per page. Scanned PDFs without text are reported as such rather than guessed at. The file is processed in memory and not stored.
