{
  "name": "xlsx-to-json",
  "summary": "Reads an Excel .xlsx into JSON rows, keyed by a header row or as arrays; dates become ISO strings. Archives are limited to 64 worksheets.",
  "rationale": "Parsing a real .xlsx needs a spreadsheet engine plus a hardened fetch: an agent fetching the URL itself walks past every SSRF control, and carrying exceljs per call is not something an agent does inline.",
  "family": "documents",
  "price_usd": "0.005",
  "free": false,
  "timeout_ms": 40000,
  "max_timeout_seconds": 61,
  "input_schema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "url": {
        "type": "string",
        "maxLength": 2048,
        "format": "uri",
        "description": "Absolute http(s) URL of the .xlsx, up to 2048 characters; redirects are followed, the body must be a zip, and exceljs must load at least one worksheet from it (at most 64)."
      },
      "sheet": {
        "description": "Exact name of the one worksheet to return, 1 to 255 characters; omitted, every worksheet is returned, and a name not in the workbook is a 422 listing the available names.",
        "type": "string",
        "minLength": 1,
        "maxLength": 255
      },
      "header_row": {
        "default": 1,
        "description": "The 1-based row holding the column names, 0 to 1000, default 1; data starts on the next row, and 0 returns every row as a positional array with columns set to null.",
        "type": "integer",
        "minimum": 0,
        "maximum": 1000
      },
      "max_rows": {
        "default": 1000,
        "description": "Maximum data rows returned per worksheet, 1 to 50000, default 1000; a sheet with more rows is cut and marked truncated.",
        "type": "integer",
        "minimum": 1,
        "maximum": 50000
      }
    },
    "required": [
      "url"
    ],
    "additionalProperties": false
  },
  "input_example": {
    "url": "https://grist.tools/samples/documents/garden-inventory.xlsx",
    "header_row": 1,
    "max_rows": 1000
  },
  "output_example": {
    "source_url": "https://grist.tools/samples/documents/garden-inventory.xlsx",
    "sheet_count": 2,
    "sheets": [
      {
        "name": "Seeds",
        "columns": [
          "Variety",
          "Crop",
          "Packets",
          "Sown On",
          "Organic"
        ],
        "rows": [
          {
            "Variety": "Early Scarlet",
            "Crop": "Radish",
            "Packets": 4,
            "Sown On": "2026-03-14T00:00:00.000Z",
            "Organic": true
          },
          {
            "Variety": "Green Arrow",
            "Crop": "Pea",
            "Packets": 6,
            "Sown On": "2026-03-21T00:00:00.000Z",
            "Organic": true
          },
          {
            "Variety": "Golden Cherry",
            "Crop": "Tomato",
            "Packets": 2,
            "Sown On": "2026-04-11T00:00:00.000Z",
            "Organic": false
          }
        ],
        "row_count": 3,
        "truncated": false
      },
      {
        "name": "Tools",
        "columns": [
          "Tool",
          "Count",
          "Location"
        ],
        "rows": [
          {
            "Tool": "Spade",
            "Count": 3,
            "Location": "Shed"
          },
          {
            "Tool": "Watering can",
            "Count": 5,
            "Location": "Rain barrels"
          }
        ],
        "row_count": 2,
        "truncated": false
      }
    ]
  },
  "errors": [
    "invalid_input",
    "blocked_target",
    "unreachable_target",
    "upstream_timeout",
    "unsupported_content_type",
    "too_large",
    "unprocessable",
    "internal"
  ]
}