Sheet Generation API: Structured JSON In, Formatted Spreadsheet Out

7 min read Sheet Generation

Spreadsheet Generation Is Still Painful

Every application eventually needs to export data as a spreadsheet. Financial reports, inventory lists, invoices, analytics dashboards — at some point, someone asks for an Excel file and you start searching for libraries.

If you work in JavaScript, you find ExcelJS or SheetJS. Python has openpyxl. Ruby has caxlsx. Java has Apache POI. Each one has a different API surface, different quirks, and different failure modes. The common thread: they’re all verbose. Generating a simple XLSX with headers, currency formatting, and a SUM formula takes dozens of lines of boilerplate — cell references, style objects, merge ranges, format strings.

CSV is simpler but limited. No formatting, no formulas, no multiple sheets. You get a flat text file and hope the recipient’s spreadsheet app guesses the delimiter correctly.

And if you need both formats? You maintain two separate code paths. One for XLSX with its style objects and cell references. One for CSV with its string concatenation. Both doing the same conceptual thing — turning rows of data into a spreadsheet — in completely different ways.

One API Call, Three Formats

The Sheet Generation API takes a single JSON payload describing your spreadsheet and returns a formatted file. The same payload produces XLSX, CSV, or Markdown — you just change the format field.

Here’s the simplest possible request:

Request
curl -X POST https://api.iterationlayer.com/sheet-generation/v1/generate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "xlsx",
    "sheets": [
      {
        "name": "Q1 Revenue",
        "columns": [
          {
            "name": "Company"
          },
          {
            "name": "Region"
          },
          {
            "name": "Revenue"
          }
        ],
        "rows": [
          [
            {
              "value": "Acme Corp"
            },
            {
              "value": "North America"
            },
            {
              "value": 48500.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ],
          [
            {
              "value": "Globex Ltd"
            },
            {
              "value": "Europe"
            },
            {
              "value": 37200.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ]
        ]
      }
    ]
  }'
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const result = await client.generateSheet({
  format: "xlsx",
  sheets: [
    {
      name: "Q1 Revenue",
      columns: [
        {
          name: "Company",
        },
        {
          name: "Region",
        },
        {
          name: "Revenue",
        },
      ],
      rows: [
        [
          {
            value: "Acme Corp",
          },
          {
            value: "North America",
          },
          {
            value: 48500.00,
            format: "currency",
            currency_code: "USD",
          },
        ],
        [
          {
            value: "Globex Ltd",
          },
          {
            value: "Europe",
          },
          {
            value: 37200.00,
            format: "currency",
            currency_code: "EUR",
          },
        ],
      ],
    },
  ],
});
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

result = client.generate_sheet(
    format="xlsx",
    sheets=[
        {
            "name": "Q1 Revenue",
            "columns": [
                {
                    "name": "Company",
                },
                {
                    "name": "Region",
                },
                {
                    "name": "Revenue",
                },
            ],
            "rows": [
                [
                    {
                        "value": "Acme Corp",
                    },
                    {
                        "value": "North America",
                    },
                    {
                        "value": 48500.00,
                        "format": "currency",
                        "currency_code": "USD",
                    },
                ],
                [
                    {
                        "value": "Globex Ltd",
                    },
                    {
                        "value": "Europe",
                    },
                    {
                        "value": 37200.00,
                        "format": "currency",
                        "currency_code": "EUR",
                    },
                ],
            ],
        },
    ],
)
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
package main

import il "github.com/iterationlayer/sdk-go"

func main() {
    client := il.NewClient("YOUR_API_KEY")

    result, err := client.GenerateSheet(il.GenerateSheetRequest{
        Format: "xlsx",
        Sheets: []il.Sheet{
            {
                Name: "Q1 Revenue",
                Columns: []il.SheetColumn{
                    {
                        Name: "Company",
                    },
                    {
                        Name: "Region",
                    },
                    {
                        Name: "Revenue",
                    },
                },
                Rows: []il.SheetRow{
                    {
                        {
                            Value: "Acme Corp",
                        },
                        {
                            Value: "North America",
                        },
                        {
                            Value:        48500.00,
                            Format:       "currency",
                            CurrencyCode: "USD",
                        },
                    },
                    {
                        {
                            Value: "Globex Ltd",
                        },
                        {
                            Value: "Europe",
                        },
                        {
                            Value:        37200.00,
                            Format:       "currency",
                            CurrencyCode: "EUR",
                        },
                    },
                },
            },
        },
    })
    if err != nil {
        panic(err)
    }
    _ = result
}
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}

The response contains the file as a base64-encoded buffer with the appropriate MIME type. Decode it, save it, send it to a client — the file is ready to open in Excel, Google Sheets, or Numbers.

The Data Model

The API uses a positional model. You define columns, then provide rows as ordered arrays of cells. Each cell has a value and optional formatting.

Columns define the header row. Each column has a name and an optional width:

{
  "columns": [
    {
      "name": "Product",
      "width": 30
    },
    {
      "name": "Units Sold"
    },
    {
      "name": "Unit Price"
    },
    {
      "name": "Total"
    }
  ]
}

Cells carry the data. At minimum, a cell has a value. Add format to control how it’s displayed:

{
  "value": 1500.50,
  "format": "currency",
  "currency_code": "USD"
}

Supported cell formats: text, number, decimal, currency, percentage, date, datetime, time, and custom.

Number styles control how digits are grouped. Four styles cover the major international conventions:

  • comma_period — 1,234.56 (US, UK, most of Asia)
  • period_comma — 1.234,56 (Germany, Brazil, most of Europe)
  • space_comma — 1 234,56 (France, Norway, Sweden)
  • space_period — 1 234.56 (Estonia, South Africa)

Currency codes follow ISO 4217. The API supports 162 codes — from USD and EUR to THB and CLP — and maps each one to its correct symbol.

Styles: Base and Per-Cell

Instead of styling every cell individually, you define base styles for headers and body rows, then override specific cells as needed.

Request
curl -X POST https://api.iterationlayer.com/sheet-generation/v1/generate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "xlsx",
    "styles": {
      "header": {
        "is_bold": true,
        "font_size_in_pt": 12,
        "background_color": "#1a1a2e",
        "font_color": "#ffffff",
        "horizontal_alignment": "center"
      },
      "body": {
        "font_size_in_pt": 10
      }
    },
    "sheets": [
      {
        "name": "Styled Report",
        "columns": [
          {
            "name": "Item"
          },
          {
            "name": "Amount"
          }
        ],
        "rows": [
          [
            {
              "value": "Server costs"
            },
            {
              "value": 4200.00,
              "format": "currency",
              "currency_code": "USD",
              "styles": {
                "font_color": "#cc0000"
              }
            }
          ]
        ]
      }
    ]
  }'
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const result = await client.generateSheet({
  format: "xlsx",
  styles: {
    header: {
      is_bold: true,
      font_size_in_pt: 12,
      background_color: "#1a1a2e",
      font_color: "#ffffff",
      horizontal_alignment: "center",
    },
    body: {
      font_size_in_pt: 10,
    },
  },
  sheets: [
    {
      name: "Styled Report",
      columns: [
        {
          name: "Item",
        },
        {
          name: "Amount",
        },
      ],
      rows: [
        [
          {
            value: "Server costs",
          },
          {
            value: 4200.00,
            format: "currency",
            currency_code: "USD",
            styles: {
              font_color: "#cc0000",
            },
          },
        ],
      ],
    },
  ],
});
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

result = client.generate_sheet(
    format="xlsx",
    styles={
        "header": {
            "is_bold": True,
            "font_size_in_pt": 12,
            "background_color": "#1a1a2e",
            "font_color": "#ffffff",
            "horizontal_alignment": "center",
        },
        "body": {
            "font_size_in_pt": 10,
        },
    },
    sheets=[
        {
            "name": "Styled Report",
            "columns": [
                {
                    "name": "Item",
                },
                {
                    "name": "Amount",
                },
            ],
            "rows": [
                [
                    {
                        "value": "Server costs",
                    },
                    {
                        "value": 4200.00,
                        "format": "currency",
                        "currency_code": "USD",
                        "styles": {
                            "font_color": "#cc0000",
                        },
                    },
                ],
            ],
        },
    ],
)
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
package main

import il "github.com/iterationlayer/sdk-go"

func main() {
    client := il.NewClient("YOUR_API_KEY")

    result, err := client.GenerateSheet(il.GenerateSheetRequest{
        Format: "xlsx",
        Styles: &il.SheetStyles{
            Header: &il.CellStyle{
                IsBold:              true,
                FontSizeInPt:        12,
                BackgroundColor:     "#1a1a2e",
                FontColor:           "#ffffff",
                HorizontalAlignment: "center",
            },
            Body: &il.CellStyle{
                FontSizeInPt: 10,
            },
        },
        Sheets: []il.Sheet{
            {
                Name: "Styled Report",
                Columns: []il.SheetColumn{
                    {
                        Name: "Item",
                    },
                    {
                        Name: "Amount",
                    },
                },
                Rows: []il.SheetRow{
                    {
                        {
                            Value: "Server costs",
                        },
                        {
                            Value:        4200.00,
                            Format:       "currency",
                            CurrencyCode: "USD",
                            Styles: &il.CellStyle{
                                FontColor: "#cc0000",
                            },
                        },
                    },
                },
            },
        },
    })
    if err != nil {
        panic(err)
    }
    _ = result
}
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}

The styles.header and styles.body objects set defaults. The styles field on individual cells overrides them. Available style properties include font_family, font_size_in_pt, is_bold, is_italic, font_color, background_color, horizontal_alignment, and number_format.

For XLSX output, you can also embed custom fonts by including a fonts array with base64-encoded font buffers.

Formulas

Cells whose value starts with = are treated as formulas. In XLSX output, they’re written as native Excel formulas — Excel evaluates them when the file opens. In CSV and Markdown output, the API evaluates them server-side and writes the computed result.

The server-side evaluator supports SUM, AVERAGE, COUNT, MIN, and MAX on cell ranges.

{
  "sheets": [
    {
      "name": "Invoice",
      "columns": [
        {
          "name": "Description"
        },
        {
          "name": "Amount"
        }
      ],
      "rows": [
        [
          {
            "value": "Design work"
          },
          {
            "value": 3200,
            "format": "currency",
            "currency_code": "USD"
          }
        ],
        [
          {
            "value": "Development"
          },
          {
            "value": 8500,
            "format": "currency",
            "currency_code": "USD"
          }
        ],
        [
          {
            "value": "QA testing"
          },
          {
            "value": 1500,
            "format": "currency",
            "currency_code": "USD"
          }
        ],
        [
          {
            "value": "Total"
          },
          {
            "value": "=SUM(B2:B4)",
            "format": "currency",
            "currency_code": "USD"
          }
        ]
      ]
    }
  ]
}

In XLSX, the Total cell contains =SUM(B2:B4) and Excel computes it. In CSV, the API evaluates the formula and writes 13200. Same input, correct output in every format.

Cell Merging

Cells can span multiple columns and rows using from_col, to_col, from_row, and to_row. This works in XLSX output for building headers that span columns or summary rows that stretch across a table.

{
  "value": "Q1 2026 Financial Summary",
  "from_col": 0,
  "to_col": 3,
  "styles": {
    "is_bold": true,
    "horizontal_alignment": "center",
    "font_size_in_pt": 14
  }
}

The Pipeline: Extract Then Generate

The Sheet Generation API is designed to compose with the Document Extraction API. A common workflow: you receive invoices as PDFs, extract the line items, and generate a consolidated spreadsheet.

Request
# Step 1: Extract invoice data
EXTRACTION=$(curl -s -X POST https://api.iterationlayer.com/document-extraction/v1/extract \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "'"$INVOICE_PDF_BASE64"'",
    "schema": {
      "vendor": {
        "type": "text"
      },
      "invoice_number": {
        "type": "text"
      },
      "line_items": {
        "type": "array",
        "items": {
          "description": {
            "type": "text"
          },
          "quantity": {
            "type": "number"
          },
          "unit_price": {
            "type": "currency"
          },
          "total": {
            "type": "currency"
          }
        }
      }
    }
  }')

# Step 2: Generate the spreadsheet from extracted data
curl -X POST https://api.iterationlayer.com/sheet-generation/v1/generate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "xlsx",
    "styles": {
      "header": {
        "is_bold": true,
        "background_color": "#f0f0f0"
      }
    },
    "sheets": [
      {
        "name": "Invoice",
        "columns": [
          {
            "name": "Description"
          },
          {
            "name": "Quantity"
          },
          {
            "name": "Unit Price"
          },
          {
            "name": "Total"
          }
        ],
        "rows": [
          [
            {
              "value": "Design work"
            },
            {
              "value": 1,
              "format": "number"
            },
            {
              "value": 3200,
              "format": "currency",
              "currency_code": "USD"
            },
            {
              "value": 3200,
              "format": "currency",
              "currency_code": "USD"
            }
          ],
          [
            {
              "value": "Development"
            },
            {
              "value": 1,
              "format": "number"
            },
            {
              "value": 8500,
              "format": "currency",
              "currency_code": "USD"
            },
            {
              "value": 8500,
              "format": "currency",
              "currency_code": "USD"
            }
          ]
        ]
      }
    ]
  }'
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

// Step 1: Extract invoice data
const extraction = await client.extract({
  file: invoicePdfBase64,
  schema: {
    vendor: {
      type: "text",
    },
    invoice_number: {
      type: "text",
    },
    line_items: {
      type: "array",
      items: {
        description: {
          type: "text",
        },
        quantity: {
          type: "number",
        },
        unit_price: {
          type: "currency",
        },
        total: {
          type: "currency",
        },
      },
    },
  },
});

const fields = extraction.data.fields;

// Step 2: Generate the spreadsheet
const rows = fields.line_items.value.map((item) => [
  {
    value: item.description.value,
  },
  {
    value: item.quantity.value,
    format: "number",
  },
  {
    value: item.unit_price.value,
    format: "currency",
    currency_code: "USD",
  },
  {
    value: item.total.value,
    format: "currency",
    currency_code: "USD",
  },
]);

const sheet = await client.generateSheet({
  format: "xlsx",
  styles: {
    header: {
      is_bold: true,
      background_color: "#f0f0f0",
    },
  },
  sheets: [
    {
      name: `Invoice ${fields.invoice_number.value}`,
      columns: [
        {
          name: "Description",
        },
        {
          name: "Quantity",
        },
        {
          name: "Unit Price",
        },
        {
          name: "Total",
        },
      ],
      rows,
    },
  ],
});
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

# Step 1: Extract invoice data
extraction = client.extract(
    file=invoice_pdf_base64,
    schema={
        "vendor": {
            "type": "text",
        },
        "invoice_number": {
            "type": "text",
        },
        "line_items": {
            "type": "array",
            "items": {
                "description": {
                    "type": "text",
                },
                "quantity": {
                    "type": "number",
                },
                "unit_price": {
                    "type": "currency",
                },
                "total": {
                    "type": "currency",
                },
            },
        },
    },
)

fields = extraction.data.fields

# Step 2: Generate the spreadsheet
rows = [
    [
        {
            "value": item.description.value,
        },
        {
            "value": item.quantity.value,
            "format": "number",
        },
        {
            "value": item.unit_price.value,
            "format": "currency",
            "currency_code": "USD",
        },
        {
            "value": item.total.value,
            "format": "currency",
            "currency_code": "USD",
        },
    ]
    for item in fields.line_items.value
]

sheet = client.generate_sheet(
    format="xlsx",
    styles={
        "header": {
            "is_bold": True,
            "background_color": "#f0f0f0",
        },
    },
    sheets=[
        {
            "name": f"Invoice {fields.invoice_number.value}",
            "columns": [
                {
                    "name": "Description",
                },
                {
                    "name": "Quantity",
                },
                {
                    "name": "Unit Price",
                },
                {
                    "name": "Total",
                },
            ],
            "rows": rows,
        },
    ],
)
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
package main

import il "github.com/iterationlayer/sdk-go"

func main() {
    client := il.NewClient("YOUR_API_KEY")

    // Step 1: Extract invoice data
    extraction, err := client.Extract(il.ExtractRequest{
        File: invoicePdfBase64,
        Schema: map[string]il.SchemaField{
            "vendor": {
                Type: "text",
            },
            "invoice_number": {
                Type: "text",
            },
            "line_items": {
                Type: "array",
                Items: map[string]il.SchemaField{
                    "description": {
                        Type: "text",
                    },
                    "quantity": {
                        Type: "number",
                    },
                    "unit_price": {
                        Type: "currency",
                    },
                    "total": {
                        Type: "currency",
                    },
                },
            },
        },
    })
    if err != nil {
        panic(err)
    }

    fields := extraction.Data.Fields

    // Step 2: Generate the spreadsheet
    var rows []il.SheetRow
    for _, item := range fields.LineItems.Value {
        rows = append(rows, il.SheetRow{
            {
                Value: item.Description.Value,
            },
            {
                Value:  item.Quantity.Value,
                Format: "number",
            },
            {
                Value:        item.UnitPrice.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
            {
                Value:        item.Total.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
        })
    }

    sheet, err := client.GenerateSheet(il.GenerateSheetRequest{
        Format: "xlsx",
        Styles: &il.SheetStyles{
            Header: &il.CellStyle{
                IsBold:          true,
                BackgroundColor: "#f0f0f0",
            },
        },
        Sheets: []il.Sheet{
            {
                Name: "Invoice " + fields.InvoiceNumber.Value,
                Columns: []il.SheetColumn{
                    {
                        Name: "Description",
                    },
                    {
                        Name: "Quantity",
                    },
                    {
                        Name: "Unit Price",
                    },
                    {
                        Name: "Total",
                    },
                },
                Rows: rows,
            },
        },
    })
    if err != nil {
        panic(err)
    }
    _ = sheet
}
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}

PDF in, formatted XLSX out. Two API calls, no local dependencies.

Get Started

The Sheet Generation API is available now. Check the docs for the full API reference, including all cell formats, style properties, and formula support.

If you’re already using the Document Extraction API, the two compose naturally — extraction output maps directly to sheet rows. If you’re starting fresh, the Sheet Generation quickstart is the fastest path to your first generated spreadsheet.

Sign up for a free account — no credit card required — and generate your first spreadsheet in minutes.

Start building in minutes

Free trial included. No credit card required.