- name
- google-sheets
- description
- Google Sheets: Work with Google Sheets using safe short actions: discover tabs and headers, read values with exact one-based row numbers, append rows and columns, update selected fields, archive and delete rows, read and manage. Use when an agent needs google sheets, google sheets api, append spreadsheet rows safely, update crm style rows by key, export a sheet to csv or pdf, create reporting spreadsheets, add conditional formatting, spreadsheet id through AgentPMT-hosted remote tool calls.
- version
- 1.0.1
- homepage
- https://www.agentpmt.com/marketplace/google-sheets-api
- compatibility
- Agent instructions for AgentPMT-hosted remote tool calls. Follow this skill body for supported account, wallet, and setup routes. No local command runtime is declared.
- metadata
- {"author":"agentpmt","openclaw":{"homepage":"https://www.agentpmt.com/marketplace/google-sheets-api"}}
# Google Sheets
## Freshness
Last updated: `2026-10-04`.
If the current date is more than 7 days after the last updated date, reinstall this skill from skills.sh or ClawHub before relying on endpoints, schemas, setup steps, or examples.
## What This Tool Does
Create, read, update, format, share, and export Google Sheets with agent-safe spreadsheet workflows. Append rows after Google's detected table, read cell notes with exact locations and values, delete selected worksheet rows, update fields by one-based row number or stable key, and store exports in File Manager.
## Product Instructions
### Google Sheets
Use the short action names. This tool is optimized for safe agent workflows:
read a tab, append rows after Google's detected table, update only named columns in a
matched row, and export a specific sheet without guessing `"Sheet1"`.
#### Use These First
- Read data: `read`
- Add table records: `append_rows`
- Add one new field/column: `append_column`
- Update selected fields in a matched row: `update_row`
- Export one tab or the whole spreadsheet: `export_sheet`
- Discover real tab names: `list_sheets`
- Read notes with their cells and current values: `list_notes`
- Remove selected worksheet rows after verifying their data is safely copied: `delete_rows`
#### Actions
- `create`
- `search`
- `list_sheets`
- `read`
- `get_headers`
- `get_data_range`
- `list_notes`
- `set_note`
- `delete_note`
- `append_rows`
- `append_column`
- `update_row`
- `export_sheet`
- `share`
- `add_sheet`
- `delete_sheet`
- `delete_rows`
- `rename_sheet`
- `sort`
- `find_replace`
- `format_cells`
- `protect_range`
- `unprotect_range`
- `add_named_range`
- `delete_named_range`
- `set_data_validation`
- `add_conditional_formatting`
- `copy_paste`
- `cut_paste`
- `get_instructions`
Legacy low-level names such as `get_values`, `append_values`,
`batch_update_values`, `get_sheet_data`, `create_spreadsheet`, and raw
`batch_update` are intentionally removed. Use the friendly action that matches
the intent instead.
#### Safe Reads
If `sheet_name` is omitted, the tool resolves the real first tab from
spreadsheet metadata. Do not guess `"Sheet1"`.
Use the exact tab title from `list_sheets` for `sheet_name`, without A1 quote
marks: `"Oct 2026"`, not `"'Oct 2026'"`. Quote tab names only inside a
fully qualified A1 `range`, for example `"'Oct 2026'!A2:I2"`. For one-tab
actions, use either a sheet selector with an unqualified range or a qualified
range by itself. On `read`, conflicting selectors are rejected. Cross-tab
`copy_paste` and `cut_paste` may use separately qualified source and destination
ranges.
All row numbers exposed by this tool are **one-based worksheet row numbers**,
matching the row labels visible in Google Sheets. `read` returns `row_numbers`
aligned with `values`: `values[i]` is on sheet row `row_numbers[i]`. Use that
number directly for `update_row` or `delete_rows`; do not add 1 or 2. For
example, when row 1 is the header, `values[1]` has `row_numbers[1] == 2`.
This also works when `read` starts at a later range such as `A20:I30`.
```json
{"action": "read", "spreadsheet_id": "1abc..."}
```
```json
{"action": "read", "spreadsheet_id": "1abc...", "sheet_name": "Q1 Pipeline", "range": "A1:D20"}
```
`get_data_range.last_row` is also an absolute, one-based sheet row number.
Call `get_data_range` without `range` to get `recommended_append_start` for the
whole tab. If a partial `range` is supplied, the recommendation is `null`
because the tool cannot know whether data exists outside that selection.
#### Append Rows
Use `append_rows` for all table appends. The tool reads headers when rows are
objects, maps keys to columns, and appends with `INSERT_ROWS`.
```json
{
"action": "append_rows",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"rows": [
{"Name": "Ada", "Status": "New"},
{"Name": "Grace", "Status": "Qualified"}
]
}
```
The backend also accepts array rows, but the published vendor action schema
exposes object rows. Agents should use header-keyed objects so the columns are
unambiguous.
`append_rows` does not take a destination row number. Google places the new
rows after the table it detects in the requested tab; read the returned
`appended_row_numbers` (or `updates.updatedRange`) for their actual sheet
positions. Do not calculate an insertion row or add an offset. If exact
placement within the sheet is required, `append_rows` is not that operation.
#### Append Column
Use `append_column` to add a column immediately after the current data table.
Agents should not calculate raw column indexes.
```json
{
"action": "append_column",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"column_name": "Owner",
"column_values": ["Sam", "Riley"]
}
```
#### Update A Row Safely
Use `update_row` to update specific fields only. The tool resolves headers and
emits exact `updateCells` requests for the touched cells.
```json
{
"action": "update_row",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"key_column": "Email",
"key_value": "ada@example.com",
"updates": {"Status": "Qualified", "Owner": "Sam"}
}
```
If more than one row matches, the tool errors unless `multi` is `true`.
For a known physical row, pass `row_number` directly from `read.row_numbers`:
```json
{"action": "update_row", "spreadsheet_id": "1abc...", "sheet_name": "Leads", "row_number": 8, "updates": {"Status": "Qualified"}}
```
Prefer `row_number` over matching an entire long text cell with `key_column`
and `key_value`; even a changed newline or punctuation mark makes an exact
text match fail. Re-read immediately before an update if other writers may
insert or delete rows.
#### Delete Rows
`delete_rows` permanently removes complete worksheet rows and shifts the rows
below them upward. Required: `spreadsheet_id`, one of `sheet_name`, `sheet_id`,
or `sheet_index`, and `row_numbers` (an array of 1-500 distinct, one-based row
numbers). Row 1 is protected. The tool deletes the original row numbers from
bottom to top, so non-adjacent rows can be sent together without recalculating
positions. Never retry a successful or uncertain deletion with the same row
numbers; re-read the sheet first because positions may have shifted.
```json
{"action": "delete_rows", "spreadsheet_id": "1abc...", "sheet_name": "Posts", "row_numbers": [3, 8, 12]}
```
For archiving values: read the source rows, send their values to the archive
tab with `append_rows`, verify the returned appended rows, then delete only the
original source row numbers in one `delete_rows` call. If formatting or notes
must also move, use `copy_paste` or `cut_paste` into a verified empty archive
range instead; these actions overwrite destination cells and do not insert
worksheet rows. After `cut_paste`, the source cells are blank but the worksheet
rows remain until `delete_rows` runs. Do not delete rows before verifying the
archive.
For example, if a `posted` record is `read.values[1]` and its matching
`read.row_numbers[1]` is `2`, move `A2:I2` and later delete row `2`—not row `4`.
`copy_paste` and `cut_paste` use A1 addresses such as `'Posts'!A8:I8` and
`'archive'!A3`; those row numbers are also one-based. `cut_paste` returns
`destination_row_number` for confirmation. Do not add an offset to A1 addresses.
#### Cell Notes
Notes are stable Google Sheets cell metadata and are distinct from comment
threads. `list_notes` returns each note with its exact sheet, A1 cell address,
displayed value, raw/effective value, and formula when present. With no sheet or
range filter it scans every tab in the spreadsheet.
```json
{"action": "list_notes", "spreadsheet_id": "1abc..."}
```
Limit the scan to one tab or range when the workbook is large:
```json
{"action": "list_notes", "spreadsheet_id": "1abc...", "sheet_name": "Forecast", "range": "A1:F100"}
```
Set or replace a note. When `range` contains multiple cells, the same note is
applied to every cell in the range:
```json
{"action": "set_note", "spreadsheet_id": "1abc...", "sheet_name": "Forecast", "range": "D12", "note": "Verify this assumption"}
```
Delete notes from a cell or range without changing cell values or formatting:
```json
{"action": "delete_note", "spreadsheet_id": "1abc...", "sheet_name": "Forecast", "range": "D12"}
```
#### Export
`export_sheet` stores exports in AgentPMT File Manager.
CSV and TSV exports for a specific sheet are synthesized from Sheets values
using proper CSV quoting. PDF/XLSX/ODS/HTML/ZIP exports for one sheet use the
official temporary-spreadsheet + `sheets.copyTo` + Drive export flow. Whole
spreadsheet exports use Drive `files.export`.
```json
{
"action": "export_sheet",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"format": "csv",
"filename": "leads.csv"
}
```
```json
{
"action": "export_sheet",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"format": "pdf",
"filename": "leads.pdf"
}
```
Drive scope is required for `export_sheet` formats that use Drive export and
for `share`.
#### Formatting And Controls
Use `format_cells` for common cell formatting:
```json
{
"action": "format_cells",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"range": "A1:D1",
"cell_format": {"bold": true, "background_color": {"red": 0.9, "green": 0.9, "blue": 1}}
}
```
Use `protect_range` and keep `warning_only=true` when you only want a warning:
```json
{
"action": "protect_range",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"range": "A1:D1",
"description": "Header row",
"warning_only": true
}
```
Remove protection by the returned Google `protected_range_id`:
```json
{"action": "unprotect_range", "spreadsheet_id": "1abc...", "protected_range_id": 12345}
```
#### Advanced Sheet Features
Named ranges:
```json
{
"action": "add_named_range",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"range": "A1:D20",
"name": "LeadTable"
}
```
```json
{"action": "delete_named_range", "spreadsheet_id": "1abc...", "named_range_id": "nr_123"}
```
Data validation:
```json
{
"action": "set_data_validation",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"range": "B2:B100",
"validation_rule": {
"condition": {"type": "ONE_OF_LIST", "values": [{"userEnteredValue": "New"}, {"userEnteredValue": "Qualified"}]},
"strict": true,
"showCustomUi": true
}
}
```
Conditional formatting:
```json
{
"action": "add_conditional_formatting",
"spreadsheet_id": "1abc...",
"sheet_name": "Leads",
"range": "B2:B100",
"rule": {
"booleanRule": {
"condition": {"type": "TEXT_EQ", "values": [{"userEnteredValue": "Qualified"}]},
"format": {"backgroundColor": {"red": 0.8, "green": 1, "blue": 0.8}}
}
}
}
```
Copy or cut/paste cells:
```json
{
"action": "copy_paste",
Ver en GitHub