Manage Tools
create_spreadsheet, manage_sheets, copy_sheet, batch_update_sheet, delete_rows, restore_snapshot.
create_spreadsheet
Creates a new blank spreadsheet and returns its ID and URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | ✓ | Name of the new spreadsheet |
// Response
{ "spreadsheetId": "1BxiMVs0XRA...", "url": "https://docs.google.com/spreadsheets/d/..." }manage_sheets
Add, rename, or delete tabs inside a spreadsheet using the Sheets REST API. No Apps Script required.
| Parameter | Type | Required | Description |
|---|---|---|---|
spreadsheetId | string | ✓ | Target spreadsheet |
action | enum | ✓ | add = create new tab, rename = change tab title, delete = remove tab |
sheetId | number | ✗ | Required for rename and delete. Get from list_sheets. |
title | string | ✗ | Required for add and rename. |
confirmDelete | boolean | ✗ | Required to be true when deleting a non-empty sheet. |
The confirmDelete guard
Before executing a delete, Sheetbase reads column A of the target sheet to count rows. If the sheet has data and confirmDelete is not true, the delete is blocked:
Delete blocked: sheet "Revenue" contains 243 rows of data.
Pass confirmDelete: true to permanently delete this sheet. THIS CANNOT BE UNDONE.This is an AX safety gate — agents must explicitly acknowledge destructive deletes.
Rename warning (important for agents)
A _warnings field is always returned on successful renames:
{
"ok": true,
"action": "rename",
"_warnings": [
"If other sheets contain formulas referencing the old name, they may be broken.
Google Sheets auto-updates references on rename via the UI but NOT via the API."
]
}Warning: Renaming a sheet via the API does not update cross-sheet formula references like =OldName!A1. Those formulas break silently. Google Sheets only auto-fixes references during in-app UI renames.
Cache invalidation
On every successful manage_sheets call, the sheet_snapshots cache for the spreadsheet is fully cleared so subsequent reads see fresh data.
Examples
// Add a new tab
{ "spreadsheetId": "...", "action": "add", "title": "June 2026" }
// Rename
{ "spreadsheetId": "...", "action": "rename", "sheetId": 812345678, "title": "Q3 2026" }
// Delete a non-empty sheet (requires explicit confirmation)
{ "spreadsheetId": "...", "action": "delete", "sheetId": 812345678, "confirmDelete": true }copy_sheet
Copies an existing tab to another spreadsheet using spreadsheets.sheets.copyTo.
| Parameter | Type | Required | Description |
|---|---|---|---|
spreadsheetId | string | ✓ | Source spreadsheet |
sheetId | number | ✓ | Numeric sheet ID (from list_sheets) |
destinationSpreadsheetId | string | ✓ | Target spreadsheet |
// Response — returns the new sheet's ID in the destination spreadsheet
{ "sheetId": 912345678 }Tip:
Typical template workflow:
create_spreadsheet→copy_sheet(template tab) →write_range(populate data) →format_cells(apply branding).
batch_update_sheet
Raw passthrough for the Google Sheets batchUpdate API. Use for everything not covered by other tools: charts, merges, column resize, data validation, conditional formatting.
| Parameter | Type | Required | Description |
|---|---|---|---|
spreadsheetId | string | ✓ | Target spreadsheet |
requests | object[] | ✓ | Array of raw batchUpdate request objects |
Example — auto-resize all columns
{
"spreadsheetId": "...",
"requests": [{
"autoResizeDimensions": {
"dimensions": { "sheetId": 0, "dimension": "COLUMNS", "startIndex": 0, "endIndex": 10 }
}
}]
}Example — freeze header row
{
"requests": [{
"updateSheetProperties": {
"properties": { "sheetId": 0, "gridProperties": { "frozenRowCount": 1 } },
"fields": "gridProperties.frozenRowCount"
}
}]
}Refer to the Google Sheets batchUpdate reference for the full request type catalogue.
Column structure tools
Use the focused column tools before raw batch_update_sheet JSON for common column layout edits. They resolve human-friendly ColumnRefs, block duplicate headers, and preflight formula/protected-range risks.
ColumnRef
{ "mode": "header", "value": "Order ID" }
{ "mode": "letter", "value": "C", "expectedHeader": "Status" }
{ "mode": "index", "value": 2 }mode: "header" is the recommended path for agents. expectedHeader is a drift check for letter/index targeting.
insert_column
Inserts a blank column before or after a target column.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
spreadsheetId | string | ✓ | — | Target spreadsheet |
sheetName | string | ✓ | — | Tab name |
column | ColumnRef | ✓ | — | Anchor column |
position | "before" | "after" | ✗ | "before" | Insert location relative to the anchor |
Blocked if the target column or insertion point overlaps a hard-locked protected range.
move_column
Moves a source column so it appears immediately before the destination column.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
spreadsheetId | string | ✓ | — | Target spreadsheet |
sheetName | string | ✓ | — | Tab name |
source | ColumnRef | ✓ | — | Column to move |
destination | ColumnRef | ✓ | — | Column the source should appear before |
allowFormulaStructureChange | boolean | ✗ | false | Allow moving a source column that contains formulas |
Blocked if the source column contains formulas unless explicitly allowed. Blocked if source or destination overlaps a hard-locked protected range.
delete_column
Permanently deletes one column.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
spreadsheetId | string | ✓ | — | Target spreadsheet |
sheetName | string | ✓ | — | Tab name |
column | ColumnRef | ✓ | — | Column to delete |
confirmDelete | boolean | ✓ | — | Must be true |
allowFormulaStructureChange | boolean | ✗ | false | Allow deleting a column that contains formulas |
Blocked if the column contains formulas unless explicitly allowed. Blocked if the column overlaps a hard-locked protected range.
delete_rows
Permanently deletes rows using semantic targeting and a required preview-confirm flow. Use this instead of raw batch_update_sheet row indexes.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
spreadsheetId | string | ✓ | — | Target spreadsheet |
sheetName | string | ✓ | — | Tab name |
target | object | ✓ | — | Row selector: row_numbers, a1_range, or where_column_match |
headerRow | number | ✗ | 1 | 1-based header row used for guards and previews |
confirmDelete | boolean | ✗ | false | First call previews; second call must set this to true |
previewToken | string | ✗ | — | Required on confirm; returned by the preview call |
expectedRowNumbers | number[] | ✗ | — | Required on confirm; must match preview |
expectedRowCount | number | ✗ | — | Required on confirm; must match preview |
allowHeaderRowDelete | boolean | ✗ | false | Allow deleting header/frozen rows |
allowFormulaStructureChange | boolean | ✗ | false | Allow deleting rows containing formula cells |
allowNoteGuardOverride | boolean | ✗ | false | Override structured header note guards |
Target modes
{ "mode": "row_numbers", "rowNumbers": [25, 26, 27] }
{ "mode": "a1_range", "range": "Orders!25:27" }
{ "mode": "where_column_match", "header": "status", "value": "Cancelled", "headerRow": 1 }where_column_match performs an exact match and caps matches at 500 rows. If more rows match, the tool blocks and asks for a narrower target.
Required workflow
First call without confirmation:
{
"spreadsheetId": "...",
"sheetName": "Orders",
"target": { "mode": "where_column_match", "header": "status", "value": "Cancelled" }
}The response returns status: "PREFLIGHT", target row numbers, a small row preview, warnings, and a previewToken. To delete, call the same target again with confirmDelete: true, the returned previewToken, expectedRowNumbers, and expectedRowCount.
The token is tied to the target rows and a fingerprint of their current contents. If rows or values drift between preview and confirm, the confirm call blocks and asks for a fresh preview.
Guards
delete_rows blocks by default when the target includes header/frozen rows, more than 500 rows, hard-locked protected ranges, formula cells, or structured header notes like [WARN], [FORMULA], or [LOCK].
Audit-only snapshot
Successful deletes store a delete_rows_audit record in write_history when the archived data is ≤ 2 MB. This is for forensic review only. restore_snapshot cannot re-insert deleted rows.
restore_snapshot
Lists or restores pre-write snapshots from the write_history table. Every successful write_range and transform_range call saves the previous range values before writing. delete_rows_audit entries may appear in history, but they cannot be restored.
| Parameter | Type | Required | Description |
|---|---|---|---|
spreadsheetId | string | ✓ | Target spreadsheet |
action | enum | ✓ | list = show available snapshots, restore = write a snapshot back |
snapshotId | string (UUID) | ✗ | Required for restore. Get the UUID from list. |
action: "list"
Returns the last 10 snapshots for the spreadsheet, ordered newest-first:
[
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"range_key": "Sheet1!A1:D50",
"tool_name": "write_range",
"created_at": "2026-05-13T07:45:00Z",
"rows": 49
}
]action: "restore"
Writes the before_values back to range_key using valueInputOption: RAW. Runs the same formula safety guards as a normal write — if the range now contains formulas, it will block unless allowFormulaOverwrite is set (not available on restore — resolve conflicts manually first).
Snapshot retention
prune_write_history() is called after every insert. It keeps the last 50 snapshots per user_id + spreadsheet_id. Older snapshots are permanently deleted.
AX recommended restore workflow
1. restore_snapshot(action: "list")
→ find the snapshot ID closest to before the bad write
2. restore_snapshot(action: "restore", snapshotId: "...")
→ range is written back to its previous stateWarning: Snapshots are only saved when the pre-write range is ≤ 1,000 rows and ≤ 2 MB. For large ranges, the snapshot is skipped silently. Check rows in the list output — if 0, no snapshot was taken.