The Invoice Spreadsheet Problem
Every accounting team has the same workflow. Invoices arrive as PDFs — from vendors, contractors, service providers. Someone needs to get that data into a spreadsheet for reconciliation, approval, or import into accounting software.
The manual version: open the PDF, copy the line items, paste into Excel, fix the formatting, repeat for the next invoice. The automated version usually involves an OCR service, a pile of regex to parse the output, and a separate process to generate the spreadsheet. Two different systems, two different failure modes, and a lot of glue code in between.
The core problem is the gap between extraction and generation. You get structured data out of a document, but then you need to transform it into a completely different format using a completely different tool. That’s where the bugs live.
Extract Then Generate
The Document Extraction API and the Sheet Generation API are designed to compose. The extraction output — structured JSON with typed fields — maps directly to sheet rows. No intermediate transformation layer, no format juggling.
Here’s the full pipeline: PDF in, formatted XLSX out.
Step 1: Define the Extraction Schema
First, tell the Document Extraction API what fields to look for in your invoice. The schema describes the structure you expect.
{
"vendor_name": {
"type": "text"
},
"invoice_number": {
"type": "text"
},
"invoice_date": {
"type": "date"
},
"due_date": {
"type": "date"
},
"line_items": {
"type": "array",
"items": {
"description": {
"type": "text"
},
"quantity": {
"type": "number"
},
"unit_price": {
"type": "currency"
},
"total": {
"type": "currency"
}
}
},
"subtotal": {
"type": "currency"
},
"tax": {
"type": "currency"
},
"total_due": {
"type": "currency"
}
}Step 2: Extract the Invoice Data
Send the PDF to the extraction endpoint with your schema. The API returns structured JSON with typed values and confidence scores.
curl -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_name": {
"type": "text"
},
"invoice_number": {
"type": "text"
},
"invoice_date": {
"type": "date"
},
"due_date": {
"type": "date"
},
"line_items": {
"type": "array",
"items": {
"description": {
"type": "text"
},
"quantity": {
"type": "number"
},
"unit_price": {
"type": "currency"
},
"total": {
"type": "currency"
}
}
},
"subtotal": {
"type": "currency"
},
"tax": {
"type": "currency"
},
"total_due": {
"type": "currency"
}
}
}'{
"success": true,
"data": {
"fields": {
"vendor_name": {
"value": "Acme Services LLC",
"confidence": 0.97
},
"invoice_number": {
"value": "INV-2026-0042",
"confidence": 0.99
},
"invoice_date": {
"value": "2026-03-15",
"confidence": 0.95
},
"due_date": {
"value": "2026-04-14",
"confidence": 0.94
},
"line_items": {
"value": [
{
"description": {
"value": "Consulting services",
"confidence": 0.96
},
"quantity": {
"value": 40,
"confidence": 0.98
},
"unit_price": {
"value": 150.00,
"confidence": 0.97
},
"total": {
"value": 6000.00,
"confidence": 0.97
}
}
],
"confidence": 0.96
},
"subtotal": {
"value": 6000.00,
"confidence": 0.97
},
"tax": {
"value": 495.00,
"confidence": 0.95
},
"total_due": {
"value": 6495.00,
"confidence": 0.98
}
}
}
}import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
apiKey: "YOUR_API_KEY",
});
const extractionResult = await client.extract({
file: invoiceBase64,
schema: {
vendor_name: {
type: "text",
},
invoice_number: {
type: "text",
},
invoice_date: {
type: "date",
},
due_date: {
type: "date",
},
line_items: {
type: "array",
items: {
description: {
type: "text",
},
quantity: {
type: "number",
},
unit_price: {
type: "currency",
},
total: {
type: "currency",
},
},
},
subtotal: {
type: "currency",
},
tax: {
type: "currency",
},
total_due: {
type: "currency",
},
},
});
const fields = extractionResult.data.fields;{
"success": true,
"data": {
"fields": {
"vendor_name": {
"value": "Acme Services LLC",
"confidence": 0.97
},
"invoice_number": {
"value": "INV-2026-0042",
"confidence": 0.99
},
"invoice_date": {
"value": "2026-03-15",
"confidence": 0.95
},
"due_date": {
"value": "2026-04-14",
"confidence": 0.94
},
"line_items": {
"value": [
{
"description": {
"value": "Consulting services",
"confidence": 0.96
},
"quantity": {
"value": 40,
"confidence": 0.98
},
"unit_price": {
"value": 150.00,
"confidence": 0.97
},
"total": {
"value": 6000.00,
"confidence": 0.97
}
}
],
"confidence": 0.96
},
"subtotal": {
"value": 6000.00,
"confidence": 0.97
},
"tax": {
"value": 495.00,
"confidence": 0.95
},
"total_due": {
"value": 6495.00,
"confidence": 0.98
}
}
}
}from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")
extraction_result = client.extract(
file=invoice_base64,
schema={
"vendor_name": {
"type": "text",
},
"invoice_number": {
"type": "text",
},
"invoice_date": {
"type": "date",
},
"due_date": {
"type": "date",
},
"line_items": {
"type": "array",
"items": {
"description": {
"type": "text",
},
"quantity": {
"type": "number",
},
"unit_price": {
"type": "currency",
},
"total": {
"type": "currency",
},
},
},
"subtotal": {
"type": "currency",
},
"tax": {
"type": "currency",
},
"total_due": {
"type": "currency",
},
},
)
fields = extraction_result.data.fields{
"success": true,
"data": {
"fields": {
"vendor_name": {
"value": "Acme Services LLC",
"confidence": 0.97
},
"invoice_number": {
"value": "INV-2026-0042",
"confidence": 0.99
},
"invoice_date": {
"value": "2026-03-15",
"confidence": 0.95
},
"due_date": {
"value": "2026-04-14",
"confidence": 0.94
},
"line_items": {
"value": [
{
"description": {
"value": "Consulting services",
"confidence": 0.96
},
"quantity": {
"value": 40,
"confidence": 0.98
},
"unit_price": {
"value": 150.00,
"confidence": 0.97
},
"total": {
"value": 6000.00,
"confidence": 0.97
}
}
],
"confidence": 0.96
},
"subtotal": {
"value": 6000.00,
"confidence": 0.97
},
"tax": {
"value": 495.00,
"confidence": 0.95
},
"total_due": {
"value": 6495.00,
"confidence": 0.98
}
}
}
}package main
import il "github.com/iterationlayer/sdk-go"
func main() {
client := il.NewClient("YOUR_API_KEY")
extractionResult, err := client.Extract(il.ExtractRequest{
File: invoiceBase64,
Schema: map[string]il.SchemaField{
"vendor_name": {
Type: "text",
},
"invoice_number": {
Type: "text",
},
"invoice_date": {
Type: "date",
},
"due_date": {
Type: "date",
},
"line_items": {
Type: "array",
Items: map[string]il.SchemaField{
"description": {
Type: "text",
},
"quantity": {
Type: "number",
},
"unit_price": {
Type: "currency",
},
"total": {
Type: "currency",
},
},
},
"subtotal": {
Type: "currency",
},
"tax": {
Type: "currency",
},
"total_due": {
Type: "currency",
},
},
})
if err != nil {
panic(err)
}
fields := extractionResult.Data.Fields
_ = fields
}{
"success": true,
"data": {
"fields": {
"vendor_name": {
"value": "Acme Services LLC",
"confidence": 0.97
},
"invoice_number": {
"value": "INV-2026-0042",
"confidence": 0.99
},
"invoice_date": {
"value": "2026-03-15",
"confidence": 0.95
},
"due_date": {
"value": "2026-04-14",
"confidence": 0.94
},
"line_items": {
"value": [
{
"description": {
"value": "Consulting services",
"confidence": 0.96
},
"quantity": {
"value": 40,
"confidence": 0.98
},
"unit_price": {
"value": 150.00,
"confidence": 0.97
},
"total": {
"value": 6000.00,
"confidence": 0.97
}
}
],
"confidence": 0.96
},
"subtotal": {
"value": 6000.00,
"confidence": 0.97
},
"tax": {
"value": 495.00,
"confidence": 0.95
},
"total_due": {
"value": 6495.00,
"confidence": 0.98
}
}
}
}
The extraction result gives you typed fields: fields.vendor_name.value is a string, fields.line_items.value is an array, fields.total_due.value is a number. Each field also carries a confidence score so you can flag low-confidence extractions for review.
Step 3: Build the Spreadsheet
Map the extracted data directly into the sheet generation payload. The line items become rows. The invoice metadata goes into a header section.
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": "#2d3748",
"font_color": "#ffffff"
},
"body": {
"font_size_in_pt": 10
}
},
"sheets": [
{
"name": "Invoice INV-2026-0042",
"columns": [
{
"name": "Description",
"width": 35
},
{
"name": "Quantity",
"width": 12
},
{
"name": "Unit Price",
"width": 16
},
{
"name": "Total",
"width": 16
}
],
"rows": [
[
{
"value": "Consulting services"
},
{
"value": 40,
"format": "number"
},
{
"value": 150.00,
"format": "currency",
"currency_code": "USD"
},
{
"value": 6000.00,
"format": "currency",
"currency_code": "USD"
}
],
[
{
"value": "Subtotal",
"styles": {
"is_bold": true
}
},
{
"value": null
},
{
"value": null
},
{
"value": 6000.00,
"format": "currency",
"currency_code": "USD"
}
],
[
{
"value": "Tax",
"styles": {
"is_bold": true
}
},
{
"value": null
},
{
"value": null
},
{
"value": 495.00,
"format": "currency",
"currency_code": "USD"
}
],
[
{
"value": "Total Due",
"styles": {
"is_bold": true,
"font_size_in_pt": 12
}
},
{
"value": null
},
{
"value": null
},
{
"value": 6495.00,
"format": "currency",
"currency_code": "USD",
"styles": {
"is_bold": true,
"font_size_in_pt": 12
}
}
]
]
}
]
}'{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
apiKey: "YOUR_API_KEY",
});
const lineItemRows = 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 summaryRows = [
[
{
value: "Subtotal",
styles: {
is_bold: true,
},
},
{
value: null,
},
{
value: null,
},
{
value: fields.subtotal.value,
format: "currency",
currency_code: "USD",
},
],
[
{
value: "Tax",
styles: {
is_bold: true,
},
},
{
value: null,
},
{
value: null,
},
{
value: fields.tax.value,
format: "currency",
currency_code: "USD",
},
],
[
{
value: "Total Due",
styles: {
is_bold: true,
font_size_in_pt: 12,
},
},
{
value: null,
},
{
value: null,
},
{
value: fields.total_due.value,
format: "currency",
currency_code: "USD",
styles: {
is_bold: true,
font_size_in_pt: 12,
},
},
],
];
const sheetResult = await client.generateSheet({
format: "xlsx",
styles: {
header: {
is_bold: true,
background_color: "#2d3748",
font_color: "#ffffff",
},
body: {
font_size_in_pt: 10,
},
},
sheets: [
{
name: `Invoice ${fields.invoice_number.value}`,
columns: [
{
name: "Description",
width: 35,
},
{
name: "Quantity",
width: 12,
},
{
name: "Unit Price",
width: 16,
},
{
name: "Total",
width: 16,
},
],
rows: [...lineItemRows, ...summaryRows],
},
],
});{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")
line_item_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
]
summary_rows = [
[
{
"value": "Subtotal",
"styles": {
"is_bold": True,
},
},
{
"value": None,
},
{
"value": None,
},
{
"value": fields.subtotal.value,
"format": "currency",
"currency_code": "USD",
},
],
[
{
"value": "Tax",
"styles": {
"is_bold": True,
},
},
{
"value": None,
},
{
"value": None,
},
{
"value": fields.tax.value,
"format": "currency",
"currency_code": "USD",
},
],
[
{
"value": "Total Due",
"styles": {
"is_bold": True,
"font_size_in_pt": 12,
},
},
{
"value": None,
},
{
"value": None,
},
{
"value": fields.total_due.value,
"format": "currency",
"currency_code": "USD",
"styles": {
"is_bold": True,
"font_size_in_pt": 12,
},
},
],
]
sheet_result = client.generate_sheet(
format="xlsx",
styles={
"header": {
"is_bold": True,
"background_color": "#2d3748",
"font_color": "#ffffff",
},
"body": {
"font_size_in_pt": 10,
},
},
sheets=[
{
"name": f"Invoice {fields.invoice_number.value}",
"columns": [
{
"name": "Description",
"width": 35,
},
{
"name": "Quantity",
"width": 12,
},
{
"name": "Unit Price",
"width": 16,
},
{
"name": "Total",
"width": 16,
},
],
"rows": line_item_rows + summary_rows,
},
],
){
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}package main
import il "github.com/iterationlayer/sdk-go"
func main() {
client := il.NewClient("YOUR_API_KEY")
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",
},
})
}
summaryRows := []il.SheetRow{
{
{
Value: "Subtotal",
Styles: &il.CellStyle{
IsBold: true,
},
},
{
Value: nil,
},
{
Value: nil,
},
{
Value: fields.Subtotal.Value,
Format: "currency",
CurrencyCode: "USD",
},
},
{
{
Value: "Tax",
Styles: &il.CellStyle{
IsBold: true,
},
},
{
Value: nil,
},
{
Value: nil,
},
{
Value: fields.Tax.Value,
Format: "currency",
CurrencyCode: "USD",
},
},
{
{
Value: "Total Due",
Styles: &il.CellStyle{
IsBold: true,
FontSizeInPt: 12,
},
},
{
Value: nil,
},
{
Value: nil,
},
{
Value: fields.TotalDue.Value,
Format: "currency",
CurrencyCode: "USD",
Styles: &il.CellStyle{
IsBold: true,
FontSizeInPt: 12,
},
},
},
}
rows = append(rows, summaryRows...)
sheetResult, err := client.GenerateSheet(il.GenerateSheetRequest{
Format: "xlsx",
Styles: &il.SheetStyles{
Header: &il.CellStyle{
IsBold: true,
BackgroundColor: "#2d3748",
FontColor: "#ffffff",
},
Body: &il.CellStyle{
FontSizeInPt: 10,
},
},
Sheets: []il.Sheet{
{
Name: "Invoice " + fields.InvoiceNumber.Value,
Columns: []il.SheetColumn{
{
Name: "Description",
Width: 35,
},
{
Name: "Quantity",
Width: 12,
},
{
Name: "Unit Price",
Width: 16,
},
{
Name: "Total",
Width: 16,
},
},
Rows: rows,
},
},
})
if err != nil {
panic(err)
}
_ = sheetResult
}{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}Two API calls. The PDF becomes structured data, and the structured data becomes a formatted spreadsheet. No local PDF parser, no XLSX library, no intermediate file formats.
Scaling to Multiple Invoices
The single-invoice pipeline extends naturally to batch processing. Extract all invoices, then consolidate them into one spreadsheet with multiple sheets — or one sheet with all line items.
# Extract each invoice and generate a consolidated spreadsheet.
# In practice, you'd script the extraction loop and build the
# sheets array dynamically. Here's the final generate call
# with data from three extracted invoices:
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": "#2d3748",
"font_color": "#ffffff"
}
},
"sheets": [
{
"name": "Invoice 001",
"columns": [
{
"name": "Description",
"width": 35
},
{
"name": "Quantity",
"width": 12
},
{
"name": "Unit Price",
"width": 16
},
{
"name": "Total",
"width": 16
}
],
"rows": [
[
{
"value": "Consulting services"
},
{
"value": 40,
"format": "number"
},
{
"value": 150.00,
"format": "currency",
"currency_code": "USD"
},
{
"value": 6000.00,
"format": "currency",
"currency_code": "USD"
}
]
]
},
{
"name": "Invoice 002",
"columns": [
{
"name": "Description",
"width": 35
},
{
"name": "Quantity",
"width": 12
},
{
"name": "Unit Price",
"width": 16
},
{
"name": "Total",
"width": 16
}
],
"rows": [
[
{
"value": "Design review"
},
{
"value": 8,
"format": "number"
},
{
"value": 200.00,
"format": "currency",
"currency_code": "USD"
},
{
"value": 1600.00,
"format": "currency",
"currency_code": "USD"
}
]
]
}
]
}'{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
apiKey: "YOUR_API_KEY",
});
const invoiceFiles = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"];
const sheets = await Promise.all(
invoiceFiles.map(async (filename) => {
const pdf = await Bun.file(filename).arrayBuffer();
const pdfBase64 = Buffer.from(pdf).toString("base64");
const extraction = await client.extract({
file: pdfBase64,
schema: extractionSchema,
});
const invoiceFields = extraction.data.fields;
return {
name: `Invoice ${invoiceFields.invoice_number.value}`,
columns: [
{
name: "Description",
width: 35,
},
{
name: "Quantity",
width: 12,
},
{
name: "Unit Price",
width: 16,
},
{
name: "Total",
width: 16,
},
],
rows: invoiceFields.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 consolidatedResult = await client.generateSheet({
format: "xlsx",
styles: {
header: {
is_bold: true,
background_color: "#2d3748",
font_color: "#ffffff",
},
},
sheets,
});{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")
invoice_files = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"]
sheets = []
for filename in invoice_files:
with open(filename, "rb") as f:
import base64
pdf_base64 = base64.b64encode(f.read()).decode()
extraction = client.extract(
file=pdf_base64,
schema=extraction_schema,
)
invoice_fields = extraction.data.fields
sheets.append({
"name": f"Invoice {invoice_fields.invoice_number.value}",
"columns": [
{
"name": "Description",
"width": 35,
},
{
"name": "Quantity",
"width": 12,
},
{
"name": "Unit Price",
"width": 16,
},
{
"name": "Total",
"width": 16,
},
],
"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 invoice_fields.line_items.value
],
})
consolidated_result = client.generate_sheet(
format="xlsx",
styles={
"header": {
"is_bold": True,
"background_color": "#2d3748",
"font_color": "#ffffff",
},
},
sheets=sheets,
){
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}package main
import (
"encoding/base64"
"os"
il "github.com/iterationlayer/sdk-go"
)
func main() {
client := il.NewClient("YOUR_API_KEY")
invoiceFiles := []string{"invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"}
var sheets []il.Sheet
for _, filename := range invoiceFiles {
pdfBytes, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
pdfBase64 := base64.StdEncoding.EncodeToString(pdfBytes)
extraction, err := client.Extract(il.ExtractRequest{
File: pdfBase64,
Schema: extractionSchema,
})
if err != nil {
panic(err)
}
invoiceFields := extraction.Data.Fields
var rows []il.SheetRow
for _, item := range invoiceFields.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",
},
})
}
sheets = append(sheets, il.Sheet{
Name: "Invoice " + invoiceFields.InvoiceNumber.Value,
Columns: []il.SheetColumn{
{
Name: "Description",
Width: 35,
},
{
Name: "Quantity",
Width: 12,
},
{
Name: "Unit Price",
Width: 16,
},
{
Name: "Total",
Width: 16,
},
},
Rows: rows,
})
}
consolidatedResult, err := client.GenerateSheet(il.GenerateSheetRequest{
Format: "xlsx",
Styles: &il.SheetStyles{
Header: &il.CellStyle{
IsBold: true,
BackgroundColor: "#2d3748",
FontColor: "#ffffff",
},
},
Sheets: sheets,
})
if err != nil {
panic(err)
}
_ = consolidatedResult
}{
"success": true,
"data": {
"buffer": "UEsDBBQAAAAIAA...",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
}Each invoice gets its own sheet tab. One XLSX file, all invoices, properly formatted.
When to Use This Pipeline
This extract-then-generate pattern works for any document-to-spreadsheet workflow:
- Invoices — Vendor invoices to accounts payable spreadsheets
- Receipts — Expense receipts to expense reports
- Purchase orders — PO documents to procurement tracking sheets
- Contracts — Contract terms to comparison matrices
- Bank statements — PDF statements to transaction logs
The key insight is that document structure maps cleanly to spreadsheet structure. A table in a PDF maps to rows and columns. Currency values map to formatted currency cells. Dates map to date-formatted cells. The extraction gives you typed data, and the sheet generation consumes typed data. No parsing, no regex, no format conversion in between.
Get Started
The Document Extraction docs cover schema design and field types. The Sheet Generation docs cover the full spreadsheet API including styles, formulas, and multi-sheet support.
Both APIs use the same authentication and the same response format. If you’re already using one, adding the other takes minutes. Sign up for a free account to try the pipeline yourself.