Skip to content

Workbooks API

The Workbooks API provides endpoints for uploading Excel files, managing workbooks, accessing sheet data, and performing CRUD operations on workbook resources.


Overview

Workbooks are the core data containers in CalcBridge. Each workbook represents an uploaded Excel file with:

  • Multiple Sheets: Access individual worksheets within the workbook
  • Cell Data: Read and update cell values with type preservation
  • Formula Tracking: Formulas are preserved and can be recalculated
  • Version History: Track changes over time (Enterprise tier)

Endpoints

List Workbooks

Get all workbooks for the current tenant with pagination.

GET /api/v1/workbooks

Query Parameters

Parameter Type Default Description
page integer 1 Page number (1-indexed)
page_size integer 20 Items per page (max 100)
sort_by string created_at Sort field: name, created_at, updated_at
sort_order string desc Sort direction: asc, desc
search string - Filter by name (partial match)

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/workbooks?page=1&page_size=20" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/workbooks",
    headers={"Authorization": f"Bearer {token}"},
    params={"page": 1, "page_size": 20, "search": "portfolio"}
)
workbooks = response.json()
for wb in workbooks["items"]:
    print(f"{wb['name']}: {wb['sheet_count']} sheets")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/workbooks?page=1&page_size=20',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const workbooks = await response.json();
workbooks.items.forEach(wb => {
  console.log(`${wb.name}: ${wb.sheet_count} sheets`);
});

Response

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "CLO Portfolio Q1 2026",
      "description": "Quarterly portfolio snapshot",
      "file_name": "portfolio_q1_2026.xlsx",
      "file_size": 2458624,
      "sheet_count": 5,
      "status": "ready",
      "created_by": "user@example.com",
      "created_at": "2026-01-25T09:00:00Z",
      "updated_at": "2026-01-25T10:30:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "name": "Holdings Report",
      "description": null,
      "file_name": "holdings_jan2026.xlsx",
      "file_size": 1245184,
      "sheet_count": 3,
      "status": "ready",
      "created_by": "user@example.com",
      "created_at": "2026-01-20T14:00:00Z",
      "updated_at": "2026-01-20T14:00:00Z"
    }
  ],
  "total": 25,
  "page": 1,
  "page_size": 20,
  "total_pages": 2
}

Upload Excel File

Upload an Excel file and create a new workbook.

POST /api/v1/workbooks/upload

Request

Content-Type: multipart/form-data

Field Type Required Description
file file Yes Excel file (.xlsx, .xls, .xlsm)
name string No Custom workbook name (defaults to filename)
description string No Workbook description

File Limits

Constraint Value
Max file size 100 MB
Max sheets 50
Max rows per sheet 1,000,000
Max columns per sheet 16,384

Example Request

curl -X POST https://api.calcbridge.io/api/v1/workbooks/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@portfolio.xlsx" \
  -F "name=CLO Portfolio Q1 2026" \
  -F "description=Quarterly portfolio snapshot"
import requests

with open("portfolio.xlsx", "rb") as f:
    response = requests.post(
        "https://api.calcbridge.io/api/v1/workbooks/upload",
        headers={"Authorization": f"Bearer {token}"},
        files={"file": ("portfolio.xlsx", f, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
        data={
            "name": "CLO Portfolio Q1 2026",
            "description": "Quarterly portfolio snapshot"
        }
    )
workbook = response.json()
print(f"Uploaded: {workbook['id']}")
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'CLO Portfolio Q1 2026');
formData.append('description', 'Quarterly portfolio snapshot');

const response = await fetch('https://api.calcbridge.io/api/v1/workbooks/upload', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` },
  body: formData
});
const workbook = await response.json();
console.log('Uploaded:', workbook.id);

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "CLO Portfolio Q1 2026",
  "description": "Quarterly portfolio snapshot",
  "file_name": "portfolio.xlsx",
  "file_size": 2458624,
  "sheet_count": 5,
  "status": "processing",
  "sheets": [
    {"name": "Holdings", "row_count": 150, "column_count": 45},
    {"name": "Summary", "row_count": 25, "column_count": 12},
    {"name": "Compliance", "row_count": 20, "column_count": 8},
    {"name": "Trades", "row_count": 0, "column_count": 15},
    {"name": "Reference", "row_count": 100, "column_count": 5}
  ],
  "created_by": "user@example.com",
  "created_at": "2026-01-25T09:00:00Z",
  "updated_at": "2026-01-25T09:00:00Z"
}

Error Responses

Status Error Description
400 Invalid file format File is not a valid Excel file
400 File too large File exceeds 100MB limit
400 Too many sheets Workbook has more than 50 sheets
422 Parse error Excel file could not be parsed
429 Rate limit exceeded Upload quota exceeded

Get Workbook Details

Retrieve detailed information about a specific workbook.

GET /api/v1/workbooks/{workbook_id}

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier

Query Parameters

Parameter Type Default Description
include_sheets boolean true Include sheet metadata
include_stats boolean false Include usage statistics

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/workbooks/550e8400-e29b-41d4-a716-446655440000?include_stats=true" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    f"https://api.calcbridge.io/api/v1/workbooks/{workbook_id}",
    headers={"Authorization": f"Bearer {token}"},
    params={"include_stats": True}
)
workbook = response.json()
print(f"Name: {workbook['name']}")
print(f"Sheets: {len(workbook['sheets'])}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/workbooks/${workbookId}?include_stats=true`,
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const workbook = await response.json();
console.log('Name:', workbook.name);
console.log('Sheets:', workbook.sheets.length);

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "CLO Portfolio Q1 2026",
  "description": "Quarterly portfolio snapshot",
  "file_name": "portfolio.xlsx",
  "file_size": 2458624,
  "sheet_count": 5,
  "status": "ready",
  "sheets": [
    {
      "name": "Holdings",
      "index": 0,
      "row_count": 150,
      "column_count": 45,
      "has_formulas": true,
      "formula_count": 450
    },
    {
      "name": "Summary",
      "index": 1,
      "row_count": 25,
      "column_count": 12,
      "has_formulas": true,
      "formula_count": 30
    }
  ],
  "stats": {
    "total_cells": 8250,
    "formula_cells": 480,
    "last_calculation": "2026-01-25T10:30:00Z",
    "calculation_count": 12
  },
  "created_by": "user@example.com",
  "created_at": "2026-01-25T09:00:00Z",
  "updated_at": "2026-01-25T10:30:00Z"
}

Error Responses

Status Error Description
404 Workbook not found Invalid workbook_id or access denied

List Sheets

Get all sheets in a workbook.

GET /api/v1/workbooks/{workbook_id}/sheets

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/workbooks/550e8400-e29b-41d4-a716-446655440000/sheets" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    f"https://api.calcbridge.io/api/v1/workbooks/{workbook_id}/sheets",
    headers={"Authorization": f"Bearer {token}"}
)
sheets = response.json()
for sheet in sheets:
    print(f"{sheet['name']}: {sheet['row_count']} rows")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/workbooks/${workbookId}/sheets`,
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const sheets = await response.json();
sheets.forEach(sheet => {
  console.log(`${sheet.name}: ${sheet.row_count} rows`);
});

Response

[
  {
    "name": "Holdings",
    "index": 0,
    "row_count": 150,
    "column_count": 45,
    "has_formulas": true,
    "formula_count": 450,
    "headers": ["CUSIP", "Borrower", "Par", "Price", "Spread", "Rating"]
  },
  {
    "name": "Summary",
    "index": 1,
    "row_count": 25,
    "column_count": 12,
    "has_formulas": true,
    "formula_count": 30,
    "headers": ["Metric", "Value", "Threshold", "Status"]
  }
]

Get Sheet Data

Retrieve data from a specific sheet with pagination.

GET /api/v1/workbooks/{workbook_id}/sheets/{sheet_name}/data

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier
sheet_name string Sheet name (URL-encoded if contains spaces)

Query Parameters

Parameter Type Default Description
page integer 1 Page number
page_size integer 100 Rows per page (max 1000)
start_row integer 1 Starting row number
end_row integer - Ending row number
columns string - Comma-separated column names to include
include_formulas boolean false Include formula strings
format string json Response format: json, csv

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/workbooks/550e8400-e29b-41d4-a716-446655440000/sheets/Holdings/data?page=1&page_size=50&include_formulas=true" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    f"https://api.calcbridge.io/api/v1/workbooks/{workbook_id}/sheets/Holdings/data",
    headers={"Authorization": f"Bearer {token}"},
    params={
        "page": 1,
        "page_size": 50,
        "columns": "CUSIP,Borrower,Par,Rating",
        "include_formulas": True
    }
)
data = response.json()
for row in data["rows"]:
    print(f"{row['CUSIP']}: {row['Par']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/workbooks/${workbookId}/sheets/Holdings/data?page=1&page_size=50`,
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const data = await response.json();
data.rows.forEach(row => {
  console.log(`${row.CUSIP}: ${row.Par}`);
});

Response

{
  "sheet_name": "Holdings",
  "columns": [
    {"name": "CUSIP", "type": "string", "index": 0},
    {"name": "Borrower", "type": "string", "index": 1},
    {"name": "Par", "type": "number", "index": 2},
    {"name": "Price", "type": "number", "index": 3},
    {"name": "Rating", "type": "string", "index": 4},
    {"name": "Concentration", "type": "number", "index": 5, "has_formula": true}
  ],
  "rows": [
    {
      "_row_number": 2,
      "CUSIP": "ABC123DEF",
      "Borrower": "Acme Corp",
      "Par": 500000.00,
      "Price": 99.5,
      "Rating": "Ba2",
      "Concentration": 2.5,
      "_formulas": {
        "Concentration": "=D2/SUM(D:D)*100"
      }
    },
    {
      "_row_number": 3,
      "CUSIP": "XYZ789GHI",
      "Borrower": "Tech Industries",
      "Par": 750000.00,
      "Price": 98.25,
      "Rating": "B1",
      "Concentration": 3.75,
      "_formulas": {
        "Concentration": "=D3/SUM(D:D)*100"
      }
    }
  ],
  "total_rows": 150,
  "page": 1,
  "page_size": 50,
  "total_pages": 3
}

Update Workbook

Update workbook metadata.

PATCH /api/v1/workbooks/{workbook_id}

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier

Request Body

Field Type Required Description
name string No New workbook name
description string No New description

Example Request

curl -X PATCH https://api.calcbridge.io/api/v1/workbooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CLO Portfolio Q1 2026 (Updated)",
    "description": "Updated quarterly snapshot with corrections"
  }'
import requests

response = requests.patch(
    f"https://api.calcbridge.io/api/v1/workbooks/{workbook_id}",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "name": "CLO Portfolio Q1 2026 (Updated)",
        "description": "Updated quarterly snapshot with corrections"
    }
)
workbook = response.json()
print(f"Updated: {workbook['name']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/workbooks/${workbookId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'CLO Portfolio Q1 2026 (Updated)',
      description: 'Updated quarterly snapshot with corrections'
    })
  }
);
const workbook = await response.json();
console.log('Updated:', workbook.name);

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "CLO Portfolio Q1 2026 (Updated)",
  "description": "Updated quarterly snapshot with corrections",
  "file_name": "portfolio.xlsx",
  "file_size": 2458624,
  "sheet_count": 5,
  "status": "ready",
  "created_by": "user@example.com",
  "created_at": "2026-01-25T09:00:00Z",
  "updated_at": "2026-01-25T11:00:00Z"
}

Delete Workbook

Delete a workbook and all associated data.

DELETE /api/v1/workbooks/{workbook_id}

Path Parameters

Parameter Type Description
workbook_id string (UUID) Workbook identifier

Example Request

curl -X DELETE https://api.calcbridge.io/api/v1/workbooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.delete(
    f"https://api.calcbridge.io/api/v1/workbooks/{workbook_id}",
    headers={"Authorization": f"Bearer {token}"}
)
# Returns 204 No Content on success
if response.status_code == 204:
    print("Workbook deleted")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/workbooks/${workbookId}`,
  {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${token}` }
  }
);
if (response.status === 204) {
  console.log('Workbook deleted');
}

Response

Returns 204 No Content on success.

Error Responses

Status Error Description
404 Workbook not found Invalid workbook_id or access denied
409 Workbook in use Workbook is being processed or has active scenarios

Workbook Status

Status Description
uploading File is being uploaded
processing File is being parsed and indexed
ready Workbook is ready for use
error Processing failed
recalculating Formulas are being recalculated

Supported File Formats

Extension Format Support Level
.xlsx Excel 2007+ Full support
.xls Excel 97-2003 Basic support
.xlsm Macro-enabled Excel Parsed without macros

Limitations

  • Macros (VBA): Not executed; sheets are imported as static data
  • Charts and Images: Not preserved
  • Pivot Tables: Imported as static data
  • External Links: Not resolved
  • Array Formulas: Limited support
  • Protected Sheets: Password-protected sheets cannot be read

Best Practices

  1. Use descriptive names: Make workbooks easy to identify
  2. Include descriptions: Document the purpose and source of data
  3. Organize sheets logically: Place primary data first, reference data last
  4. Keep files reasonably sized: Split very large workbooks if needed
  5. Validate before upload: Ensure the Excel file opens correctly locally
  6. Use consistent column naming: Helps with formula evaluation and mappings