# Google Sheets

## Links

- Product page URL: https://www.agentpmt.com/marketplace/google-sheets-api
- Product markdown URL: https://www.agentpmt.com/marketplace/google-sheets-api?format=agent-md
- Product JSON URL: https://www.agentpmt.com/marketplace/google-sheets-api?format=agent-json

## Overview

- Product ID: 696302894cf4309309cac7b2
- Type: connector
- Unit type: request
- Price: 500 credits
- Categories: Financial Modeling, Data Science, Mathematical Computing, Data Storage & Persistence, Data Processing, Data Formatting & Conversion, List & Array Operations, Sorting & Ordering, Finance & Accounting, Portfolio Management, E-commerce & Product Catalog, Survey & Feedback Collection, Marketing Automation, Team Collaboration & Workspaces, Task & Workflow Automation
- Generated at: 2026-10-13T02:26:41.063Z

### Page Description

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.

### Agent Description

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 cell notes, export sheets, share files, format cells, protect ranges, and copy or move ranges.

## Details

### Details

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.

### Actions

- `create` (5 credits): Create a new spreadsheet, optionally with an initial tab, headers, and rows.
- `search` (5 credits): Search or list recent Google Sheets spreadsheets.
- `list_sheets` (5 credits): List the tabs in a spreadsheet with sheet ids and dimensions.
- `read` (5 credits): Read values from a tab or A1 range. Returns one-based row_numbers aligned with values; no row offset is needed.
- `get_headers` (5 credits): Read the header row and return header-to-column mappings plus duplicate diagnostics.
- `get_data_range` (5 credits): Find the absolute one-based last non-empty row/column; a partial range never returns an append recommendation.
- `append_rows` (5 credits): Append rows after Google's detected table. Object rows map to sheet headers. Returns appended_row_numbers from Google's actual updated range.
- `append_column` (5 credits): Append one new column immediately after the last non-empty data column and write its header and values.
- `update_row` (5 credits): Update selected fields by header in a physical one-based row_number, or by a stable key; long-text exact matching is fragile.
- `export_sheet` (5 credits): Export a specific sheet or whole spreadsheet to File Manager as CSV, TSV, PDF, XLSX, ODS, HTML, or ZIP.
- `share` (5 credits): Share a spreadsheet with a user, group, domain, or anyone.
- `add_sheet` (5 credits): Add a new tab to a spreadsheet.
- `delete_sheet` (5 credits): Delete a tab by name, id, or index.
- `rename_sheet` (5 credits): Rename a tab by name, id, or index.
- `sort` (5 credits): Sort a range, preferably by header name.
- `find_replace` (5 credits): Find and replace text across the spreadsheet or one sheet.
- `format_cells` (5 credits): Apply cell formatting or number format to a range.
- `protect_range` (5 credits): Protect a range, optionally warning-only or with explicit editor emails.
- `unprotect_range` (5 credits): Remove protection by protected range id.
- `add_named_range` (5 credits): Create a named range.
- `delete_named_range` (5 credits): Delete a named range by id.
- `set_data_validation` (5 credits): Set a Sheets data validation rule on a range.
- `add_conditional_formatting` (5 credits): Add a conditional formatting rule to a range.
- `copy_paste` (5 credits): Copy cells to an A1 destination range; overwrites destination cells and does not insert rows.
- `cut_paste` (5 credits): Move cells to an A1 destination start cell; does not insert rows. Returns destination_row_number.
- `list_notes` (5 credits): List cell notes with exact sheet and A1 locations plus the current cell values. Without a filter, scans every tab.
- `set_note` (5 credits): Set the same note on every cell in a bounded A1 cell or range.
- `delete_note` (5 credits): Remove notes from every cell in a bounded A1 cell or range without changing values or formatting.
- `delete_rows` (5 credits): Permanently delete complete worksheet rows by original one-based row number, from bottom to top. Requires a tab selector; row 1 is protected.

### Use Cases

append spreadsheet rows safely, update CRM-style rows by key, export a sheet to CSV or PDF, create reporting spreadsheets, add data validation to templates, protect header ranges, share sheets with collaborators, copy or move spreadsheet ranges, format dashboards, manage sheet tabs

### Workflows Using This Tool

#### Plaud Recordings to Google Drive Sync

Automatically backs up your Plaud recordings to Google Drive and keeps a tracking spreadsheet in Google Sheets. Each time you run this workflow, it downloads any new recordings from your Plaud account to a "Plaud Recordings" folder in Drive, creates a transcript for each recording (using Plaud's built-in transcripts when available, or automatic speech-to-text otherwise), saves the transcript alongside the audio file, identifies what each recording is about (meeting, interview, note, etc.), and logs everything in a spreadsheet with links to the audio and transcript files. You can run this as often as you like - it only processes new recordings and won't duplicate anything. Just connect your Plaud, Google Drive, and Google Sheets accounts and run it whenever you want to sync your latest recordings.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-recordings-to-google-drive-sync
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-recordings-to-google-drive-sync?format=agent-md
- Published: 2026-08-07T14:43:24.041Z

#### Narrated Walkthrough to a Numbered SOP Document

Turns talking through a job out loud into a written, numbered standard operating procedure. Built for the people who actually know the equipment and have no time to write documentation: maintenance and facilities teams, field service, manufacturing, labs, franchise operations, and any owner trying to get a process out of their own head before handing it over. Walk the machine or the task and narrate it, saying the step number out loud as you go, and the workflow pulls the transcript of each new Plaud recording and turns it into a clean procedure document: a title, the equipment or process it covers, tools and safety notes gathered into their own sections, then numbered steps in the order you said them, with your asides and warnings kept attached to the step they belong to. Filler, false starts and interruptions are dropped; the technical content is left in your words rather than rewritten into corporate documentation voice. It lands as a Google Doc so it stays editable and exports to PDF or Word, and anything the narration left ambiguous is flagged at the end for you to fill in rather than being invented. Say each step number aloud and the transcript carries its own index, which makes pairing photos to steps afterwards mechanical instead of guesswork.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/narrated-walkthrough-to-a-numbered-sop-document
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/narrated-walkthrough-to-a-numbered-sop-document?format=agent-md
- Published: 2026-07-26T00:01:54.152Z

#### One Plaud Recording, Several Differently Formatted Summaries

Gets you past the one-template-per-recording ceiling. The Plaud app applies a single AutoFlow template to a recording, so if you want a short recap for yourself, a decisions-only version for the people who missed it, and a clean action list for your task manager, you are re-running or rewriting by hand. This workflow reads the transcript once and produces every format you have defined in a single pass: you list the output formats you want in a Google Sheet, each with a name and a description of the shape and audience, and the workflow generates all of them from the same source text and writes them into one Google Doc per recording with a section for each. Because every version comes from the same read of the transcript, they stay consistent with each other rather than drifting the way separately generated summaries do. Formats are yours to change at any time by editing the sheet, with no re-recording and no template juggling in the app. A processed log keeps each recording to a single pass so it can run on a schedule over everything new.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/one-plaud-recording-several-differently-formatted-summaries
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/one-plaud-recording-several-differently-formatted-summaries?format=agent-md
- Published: 2026-07-26T00:01:46.081Z

#### Plaud Transcripts Corrected With Your Own Terminology Glossary

Fixes the words your transcription keeps getting wrong, by giving the pipeline your vocabulary instead of hoping a bigger model guesses right. Every speech model mangles terms it has never seen: cell line and reagent names, drug and device names, case and matter numbers, part numbers, local spelling and number conventions, team and client names. Swapping to a different model does not fix this, because none of them have your terms either. Keep a plain Google Sheet glossary of the terms that matter, each with the spelling you want and the misfires it usually comes back as ("HEK293" for "heck two ninety three"), plus any formatting rules you need enforced, such as Swiss German ss instead of eszett or 1'000.00 number style. On each run the workflow reads the glossary, pulls the transcript of every new Plaud recording, applies the corrections to the transcript first, and only then writes the summary and action items from the corrected text, so your terminology is right everywhere downstream instead of only in the raw transcript. The corrected transcript and summary land in a Google Doc, and every correction made is listed so you can see what changed and keep tuning the glossary. Unknown terms are flagged, never silently normalized into something that looks plausible.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-transcripts-corrected-with-your-own-terminology-glossary
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-transcripts-corrected-with-your-own-terminology-glossary?format=agent-md
- Published: 2026-07-26T00:01:37.863Z

#### Plaud Recordings to Google Calendar Events

Puts the meetings you agree to out loud straight onto your Google Calendar, without Zapier in the middle. Plaud's own app has no Calendar integration, so this closes that gap directly: each new recording is scanned, the transcript pulled, and any genuine scheduling commitment spoken in it ("let's do Tuesday at 3", "I'll come back out Thursday morning") is extracted with the relative date resolved against the recording's own date and your timezone. Each one becomes a Google Calendar event with the agreed time, a title naming who and what, and the surrounding quote from the transcript in the description so you can see exactly what was said. Vague intentions with no time attached ("we should catch up sometime") are deliberately ignored rather than guessed into a slot. Because it uses the full Google Calendar connector it also reads back, so an agent can answer what your week looks like from the same connection. A Google Sheet ledger records every recording id and every event created, so a scheduled run never double-books you.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-recordings-to-google-calendar-events
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-recordings-to-google-calendar-events?format=agent-md
- Published: 2026-07-26T00:01:29.867Z

#### Plaud Spoken Field Notes to a Structured Sheet

Turns a spoken site visit into a filled-in spreadsheet row, so measurements and specs never get typed up twice. Built for anyone who dictates structured details on the job rather than writing them down: window and flooring measurements, equipment specs, inspection findings, punch lists, service call notes. Say the details out loud in the same order each visit (client, room, width, drop, colour, notes) and the workflow reads each new Plaud recording, pulls its transcript, extracts only the values actually spoken, and appends them as one row to your Google Sheet under whatever column headers you have already set up. Values are never inferred: if a measurement was not said, the cell is left empty and flagged in the run summary rather than guessed, because a fabricated number on a quote is worse than a blank one. Recordings that are not field dictations (meetings, personal memos, ambient audio) are logged as skipped and produce no row. A Processed tab records every recording id so the workflow can run on a schedule without duplicating rows. Pair it with your own quote template and the spreadsheet row becomes the quote.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-spoken-field-notes-to-a-structured-sheet
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-spoken-field-notes-to-a-structured-sheet?format=agent-md
- Published: 2026-07-26T00:01:20.998Z

#### Plaud Spoken Commitments to Telegram Reminders

Catches every date and time you commit to out loud in your Plaud recordings — "I'll send it Thursday", "meet Bob at 3" — and sends the whole batch to you on Telegram. Scans each new recording, pulls the transcript (reusing the recording's own transcript when one exists), extracts spoken commitments and resolves relative dates against the recording date and your timezone, and logs them to a "Plaud Commitments" Google Sheet. Every run then sends one Telegram digest listing all open commitments sorted by due date, with overdue items flagged. Mark a row "done" in the sheet to drop it from future digests. Schedule it daily and the digest becomes your morning commitments briefing — no phone number needed: connect once through the AgentPMT Telegram bot, and if you haven't yet, the run summary walks you through it. A processed-recordings tab guarantees each recording is scanned exactly once.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-spoken-commitments-to-sms-reminders
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-spoken-commitments-to-sms-reminders?format=agent-md
- Published: 2026-07-22T14:01:25.974Z

#### Plaud Client Follow-Up Email Drafter

Drafts a follow-up email after every client call you record with Plaud — and never sends without your approval. Reviews each new recording, pulls the transcript (reusing the recording's own transcript when one exists), identifies genuine client conversations, and drafts a warm, concise follow-up recapping the discussion, what each side committed to, and the agreed next step — written strictly from what was said. Looks up the client's email address in your Google Contacts, then sends you the draft with the proposed recipient for approval; only after you approve (and confirm the address) is the email sent from your own Gmail account, so it lands in your Sent folder and replies come back to you. Every recording is logged in a Google Sheet so nothing is drafted twice. Skipped and rejected drafts are recorded with their reason.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-client-follow-up-email-drafter
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-client-follow-up-email-drafter?format=agent-md
- Published: 2026-07-22T04:40:53.556Z

#### Plaud Meeting Recap to Slack

Posts a clean, speaker-labeled recap of every team meeting you record with Plaud into a Slack channel of your choice (defaults to #meeting-recaps). Reviews each new recording, pulls the transcript (reusing the recording's own transcript when one exists), identifies genuine multi-person team meetings — solo memos, client calls, and test recordings are skipped — and posts a formatted recap with participants, decisions, topics discussed, and action items with owners. A Google Sheet ledger guarantees each recording is handled exactly once, so the workflow can run on a schedule without duplicate posts. The Slack app must be a member of the target channel.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-meeting-recap-to-slack
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-meeting-recap-to-slack?format=agent-md
- Published: 2026-07-22T04:25:40.501Z

#### Plaud Master Action-Item Tracker

Collects every action item spoken in your Plaud recordings into one master Google Sheet. Scans each new recording, pulls its transcript (reusing the recording's own transcript when one exists) and AI summary, extracts concrete tasks with the responsible owner and any spoken due date (resolved to a real calendar date from the recording date), and appends them to an "Action Items" tab with status "open" — deduplicated within and across meetings so the same commitment never appears twice. A "Processed Recordings" tab guarantees each recording is scanned exactly once, so the workflow can run on a schedule. Solves the problem of action items being trapped inside individual meeting summaries.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-master-action-item-tracker
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-master-action-item-tracker?format=agent-md
- Published: 2026-07-22T04:22:11.630Z

#### Plaud Call Logger for Pipedrive

Turns your Plaud voice recordings of client calls into Pipedrive records automatically. Reviews every new recording, identifies genuine client conversations, transcribes them (reusing the recording's own transcript when one exists), saves the transcript to a "Plaud Call Logs" Drive folder, matches the spoken client name and company to a Pipedrive person and open deal, attaches a call note with the discussion summary, commitments, next steps, and transcript link, and creates a follow-up activity dated from spoken commitments. Keeps a Google Sheet ledger so every recording is processed exactly once; recordings that are not client calls are logged and skipped. Re-runnable and idempotent.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/plaud-call-logger-for-pipedrive
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/plaud-call-logger-for-pipedrive?format=agent-md
- Published: 2026-07-22T04:22:05.790Z

#### X (Twitter) Thought Leadership Engine: Human-Voice AI Posts from Industry News with Approval and Auto-Publish

Stay visible on X (Twitter) every week without staring at a blank compose box. Give this AI social media workflow your beats and your positioning, and it scans the last week of industry news, picks the strongest non-overlapping angles, and writes opinionated, fact-backed posts in a natural human voice that sounds like you, not a press release. Every post is screened by an automated writing quality check that strips robotic, overused AI phrasing, and posts that benefit from a visual get a custom 16:9 image. All drafts queue in a Google Sheet and come to you for batch approval, and the workflow checks back for your decision at 5 and 10 minutes. Approve and it publishes to X, attaching images and links correctly, then marks each row with the live post link so you keep a complete content log. Miss the window and nothing posts: every draft stays safely queued in the sheet, ready to approve and publish on a later run. Ideal for founders, executives, consultants, developer advocates, and marketers who want Twitter automation with editorial control: AI-generated social media posts, social SEO, personal branding, content marketing, and a consistent thought leadership presence built on real facts and a human voice.

- Page URL: https://www.agentpmt.com/agent-workflow-skills/x-thought-leadership-engine-turn-industry-news-into-human-voice-posts-with-approval-and-auto-publish
- Markdown URL: https://www.agentpmt.com/agent-workflow-skills/x-thought-leadership-engine-turn-industry-news-into-human-voice-posts-with-approval-and-auto-publish?format=agent-md
- Published: 2026-06-10T20:59:52.887Z

### Related Content

No related content is currently linked to this product.

## Documentation

No platform documentation is currently linked to this product.

## Integration Details

### DynamicMCP

- Setup page URL: https://www.agentpmt.com/dynamic-mcp
- Claude setup guide: https://www.agentpmt.com/dynamic-mcp#platform=claude
- ChatGPT setup guide: https://www.agentpmt.com/dynamic-mcp#platform=chatgpt
- Cursor setup guide: https://www.agentpmt.com/dynamic-mcp#platform=cursor
- Windsurf setup guide: https://www.agentpmt.com/dynamic-mcp#platform=windsurf

Use the local router for command-based MCP clients. It forwards requests to `https://api.agentpmt.com/mcp` and does not execute tools locally.

```bash
npm install -g @agentpmt/mcp-router
agentpmt-setup
```

### REST API

The live page renders cURL, Python, JavaScript, and Node.js examples. Logged-in users see those examples prefilled with their own API and budget credentials.

- Purchase endpoint: https://api.agentpmt.com/products/purchase
- Authorization format: `Bearer <base64(apiKey:budgetKey)>`

```bash
curl -X POST "https://api.agentpmt.com/products/purchase" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eW91ci1hcGkta2V5LWhlcmU6eW91ci1idWRnZXQta2V5LWhlcmU=" \
  -d '{
    "product_id": "696302894cf4309309cac7b2",
    "parameters": {
      "action": "create",
      "title": "example_title"
    }
  }'
```

### Autonomous Agents

Autonomous agents can access this tool through AgentAddress credit balances or direct x402 payments. Use the Autonomous Agent API reference for endpoint shapes after choosing the access pattern below.

- Autonomous Agent API reference URL: https://www.agentpmt.com/docs/api-reference/autonomous-agents
- Autonomous Agent API reference markdown URL: https://www.agentpmt.com/docs/api-reference/autonomous-agents?format=agent-md
- Credit-Based Access Using AgentAddress: https://www.agentpmt.com/docs/autonomous-agents/credit-based-tool-usage-with-agentaddress
- AgentAddress is preferred for persistent file access, stored platform state, and maximum tool use ability across repeated calls.
- Direct x402 is for independent one-off tool calls that do not require shared files or stored platform state.
- Direct x402 public payments: USDC on Base, Arbitrum, Optimism, Polygon, and Avalanche.

#### Product Skill Package

This product has a published Agent Skill package for product-specific operating instructions.

- Skill slug: google-sheets
- Version: 1.0.1
- Download SKILL.md: https://raw.githubusercontent.com/AgentPMT/agent-skills/main/skills/google-sheets/SKILL.md
- Package source: https://github.com/AgentPMT/agent-skills/tree/main/skills/google-sheets
- OpenClaw listing: https://clawhub.ai/agentpmt/google-sheets
- OpenClaw install: `openclaw skills install google-sheets`
- skills.sh install: `npx skills add AgentPMT/agent-skills --skill google-sheets`
- Last published: 2026-10-04T21:02:19.653Z

### Schema

#### Credentials

These runtime credentials should be provided under `parameters._credentials` when required.

- Google OAuth (`google_oauth`, oauth_token, required)
  Help: Connect your Google account.
  Connection ID: 69616abea90ed54743f01957

#### Parameters

- Schema type: actions

```json
{
  "actions": {
    "create": {
      "description": "Create a new spreadsheet, optionally with an initial tab, headers, and rows.",
      "properties": {
        "title": {
          "type": "string",
          "description": "Spreadsheet title.",
          "required": true
        },
        "initial_sheet_name": {
          "type": "string",
          "description": "Optional first tab name.",
          "required": false
        },
        "initial_headers": {
          "type": "array",
          "description": "Optional first header row.",
          "required": false,
          "items": {
            "type": "string"
          }
        },
        "rows": {
          "type": "array",
          "description": "Optional initial rows as arrays or objects keyed by headers.",
          "required": false,
          "items": {
            "type": "object"
          }
        }
      }
    },
    "search": {
      "description": "Search or list recent Google Sheets spreadsheets.",
      "properties": {
        "query": {
          "type": "string",
          "description": "Optional search text matched against spreadsheet name/content.",
          "required": false
        },
        "max_results": {
          "type": "integer",
          "description": "Maximum results to return, 1-100.",
          "required": false,
          "minimum": 1,
          "maximum": 100
        }
      }
    },
    "list_sheets": {
      "description": "List the tabs in a spreadsheet with sheet ids and dimensions.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        }
      }
    },
    "read": {
      "description": "Read values from a tab or A1 range. Returns one-based row_numbers aligned with values; no row offset is needed.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Optional numeric sheet id.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "Optional A1 range with visible one-based row labels. Qualified range and sheet_name must identify the same tab.",
          "required": false
        },
        "value_render_option": {
          "type": "string",
          "description": "FORMATTED_VALUE, UNFORMATTED_VALUE, or FORMULA.",
          "required": false
        }
      }
    },
    "get_headers": {
      "description": "Read the header row and return header-to-column mappings plus duplicate diagnostics.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "header_row": {
          "type": "integer",
          "description": "One-based header row, default 1.",
          "required": false,
          "minimum": 1
        }
      }
    },
    "get_data_range": {
      "description": "Find the absolute one-based last non-empty row/column; a partial range never returns an append recommendation.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "Optional partial A1 range; recommended_append_start is null when set.",
          "required": false
        }
      }
    },
    "append_rows": {
      "description": "Append rows after Google's detected table. Object rows map to sheet headers. Returns appended_row_numbers from Google's actual updated range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "rows": {
          "type": "array",
          "description": "Rows as arrays or objects keyed by headers.",
          "required": true,
          "items": {
            "type": "object"
          }
        },
        "header_row": {
          "type": "integer",
          "description": "One-based header row, default 1.",
          "required": false,
          "minimum": 1
        },
        "value_input_option": {
          "type": "string",
          "description": "USER_ENTERED or RAW.",
          "required": false
        }
      }
    },
    "append_column": {
      "description": "Append one new column immediately after the last non-empty data column and write its header and values.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "column_name": {
          "type": "string",
          "description": "New column header.",
          "required": true
        },
        "column_values": {
          "type": "array",
          "description": "Values to write below the header at the data table edge.",
          "required": true,
          "items": {
            "type": "string"
          }
        }
      }
    },
    "update_row": {
      "description": "Update selected fields by header in a physical one-based row_number, or by a stable key; long-text exact matching is fragile.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "row_number": {
          "type": "integer",
          "description": "Physical one-based row number from read.row_numbers; do not add 1 or 2.",
          "required": false,
          "minimum": 1
        },
        "key_column": {
          "type": "string",
          "description": "Header used to find the row when row_number is omitted.",
          "required": false
        },
        "key_value": {
          "type": "string",
          "description": "Value to match in key_column.",
          "required": false
        },
        "updates": {
          "type": "object",
          "description": "Column patch keyed by header names.",
          "required": true
        },
        "multi": {
          "type": "boolean",
          "description": "Allow all matching rows to update.",
          "required": false
        }
      }
    },
    "export_sheet": {
      "description": "Export a specific sheet or whole spreadsheet to File Manager as CSV, TSV, PDF, XLSX, ODS, HTML, or ZIP.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Optional numeric sheet id.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "Optional range for CSV/TSV exports.",
          "required": false
        },
        "format": {
          "type": "string",
          "description": "csv, tsv, pdf, xlsx, ods, html, or zip.",
          "required": true
        },
        "filename": {
          "type": "string",
          "description": "Optional stored filename.",
          "required": false
        },
        "expiration_days": {
          "type": "integer",
          "description": "File Manager expiration, 1-7 days.",
          "required": false,
          "minimum": 1,
          "maximum": 7
        }
      }
    },
    "share": {
      "description": "Share a spreadsheet with a user, group, domain, or anyone.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "email": {
          "type": "string",
          "description": "Email for user/group shares.",
          "required": false
        },
        "domain": {
          "type": "string",
          "description": "Domain for domain shares.",
          "required": false
        },
        "role": {
          "type": "string",
          "description": "reader, commenter, writer, organizer, fileOrganizer, or owner.",
          "required": false
        },
        "permission_type": {
          "type": "string",
          "description": "user, group, domain, or anyone.",
          "required": false
        }
      }
    },
    "add_sheet": {
      "description": "Add a new tab to a spreadsheet.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "new_sheet_name": {
          "type": "string",
          "description": "New tab name.",
          "required": true
        }
      }
    },
    "delete_sheet": {
      "description": "Delete a tab by name, id, or index.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric sheet id.",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        }
      }
    },
    "rename_sheet": {
      "description": "Rename a tab by name, id, or index.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "new_sheet_name": {
          "type": "string",
          "description": "New tab name.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric sheet id.",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        }
      }
    },
    "sort": {
      "description": "Sort a range, preferably by header name.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range to sort.",
          "required": true
        },
        "sort_specs": {
          "type": "array",
          "description": "Sort specs with header/column_name or dimensionIndex and order/sortOrder.",
          "required": true,
          "items": {
            "type": "object"
          }
        }
      }
    },
    "find_replace": {
      "description": "Find and replace text across the spreadsheet or one sheet.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "find": {
          "type": "string",
          "description": "Text or regex to find.",
          "required": true
        },
        "replacement": {
          "type": "string",
          "description": "Replacement text.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "match_case": {
          "type": "boolean",
          "description": "Case-sensitive match.",
          "required": false
        },
        "match_entire_cell": {
          "type": "boolean",
          "description": "Match entire cell contents only.",
          "required": false
        },
        "search_by_regex": {
          "type": "boolean",
          "description": "Treat find as regex.",
          "required": false
        }
      }
    },
    "format_cells": {
      "description": "Apply cell formatting or number format to a range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range to format.",
          "required": true
        },
        "cell_format": {
          "type": "object",
          "description": "Text/background/alignment/wrap formatting.",
          "required": false
        },
        "number_format": {
          "type": "object",
          "description": "Sheets numberFormat object.",
          "required": false
        }
      }
    },
    "protect_range": {
      "description": "Protect a range, optionally warning-only or with explicit editor emails.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range to protect.",
          "required": true
        },
        "description": {
          "type": "string",
          "description": "Protection description.",
          "required": false
        },
        "warning_only": {
          "type": "boolean",
          "description": "If true, warn instead of blocking edits.",
          "required": false
        },
        "editor_emails": {
          "type": "array",
          "description": "Users allowed to edit protected range.",
          "required": false,
          "items": {
            "type": "string"
          }
        }
      }
    },
    "unprotect_range": {
      "description": "Remove protection by protected range id.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "protected_range_id": {
          "type": "integer",
          "description": "Google protectedRangeId to delete.",
          "required": true
        }
      }
    },
    "add_named_range": {
      "description": "Create a named range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range.",
          "required": true
        },
        "name": {
          "type": "string",
          "description": "Named range name.",
          "required": true
        }
      }
    },
    "delete_named_range": {
      "description": "Delete a named range by id.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "named_range_id": {
          "type": "string",
          "description": "Google namedRangeId to delete.",
          "required": true
        }
      }
    },
    "set_data_validation": {
      "description": "Set a Sheets data validation rule on a range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range.",
          "required": true
        },
        "validation_rule": {
          "type": "object",
          "description": "Sheets DataValidationRule object.",
          "required": true
        }
      }
    },
    "add_conditional_formatting": {
      "description": "Add a conditional formatting rule to a range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range for the rule.",
          "required": true
        },
        "rule": {
          "type": "object",
          "description": "Sheets ConditionalFormatRule object; ranges can be omitted.",
          "required": true
        }
      }
    },
    "copy_paste": {
      "description": "Copy cells to an A1 destination range; overwrites destination cells and does not insert rows.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "source_range": {
          "type": "string",
          "description": "A1 source range.",
          "required": true
        },
        "destination_range": {
          "type": "string",
          "description": "A1 destination range.",
          "required": true
        },
        "paste_type": {
          "type": "string",
          "description": "Sheets pasteType such as PASTE_NORMAL or PASTE_VALUES.",
          "required": false
        },
        "paste_orientation": {
          "type": "string",
          "description": "NORMAL or TRANSPOSE.",
          "required": false
        }
      }
    },
    "cut_paste": {
      "description": "Move cells to an A1 destination start cell; does not insert rows. Returns destination_row_number.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Google spreadsheet id or URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "source_range": {
          "type": "string",
          "description": "A1 source range.",
          "required": true
        },
        "destination_range": {
          "type": "string",
          "description": "A1 destination start cell.",
          "required": true
        },
        "paste_type": {
          "type": "string",
          "description": "Sheets pasteType such as PASTE_NORMAL or PASTE_VALUES.",
          "required": false
        }
      }
    },
    "list_notes": {
      "description": "List cell notes with exact sheet and A1 locations plus the current cell values. Without a filter, scans every tab.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Spreadsheet ID or full Google Sheets URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric Google sheetId (gid).",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range using visible one-based worksheet row numbers; quote a tab name only inside a qualified range.",
          "required": false
        }
      }
    },
    "set_note": {
      "description": "Set the same note on every cell in a bounded A1 cell or range.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Spreadsheet ID or full Google Sheets URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric Google sheetId (gid).",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range using visible one-based worksheet row numbers; quote a tab name only inside a qualified range.",
          "required": true
        },
        "note": {
          "type": "string",
          "description": "Note text to set; use delete_note to remove it.",
          "required": true,
          "minLength": 1
        }
      }
    },
    "delete_note": {
      "description": "Remove notes from every cell in a bounded A1 cell or range without changing values or formatting.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Spreadsheet ID or full Google Sheets URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric Google sheetId (gid).",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        },
        "range": {
          "type": "string",
          "description": "A1 range using visible one-based worksheet row numbers; quote a tab name only inside a qualified range.",
          "required": true
        }
      }
    },
    "delete_rows": {
      "description": "Permanently delete complete worksheet rows by original one-based row number, from bottom to top. Requires a tab selector; row 1 is protected.",
      "properties": {
        "spreadsheet_id": {
          "type": "string",
          "description": "Spreadsheet ID or full Google Sheets URL.",
          "required": true
        },
        "sheet_name": {
          "type": "string",
          "description": "Exact tab title from list_sheets, without surrounding A1 quote marks.",
          "required": false
        },
        "sheet_id": {
          "type": "integer",
          "description": "Numeric Google sheetId (gid).",
          "required": false
        },
        "sheet_index": {
          "type": "integer",
          "description": "Zero-based tab index.",
          "required": false
        },
        "row_numbers": {
          "type": "array",
          "description": "Distinct original one-based sheet row numbers, each at least 2; 1-500 entries. One of sheet_name, sheet_id, or sheet_index is required.",
          "required": true,
          "minItems": 1,
          "maxItems": 500,
          "uniqueItems": true,
          "items": {
            "type": "integer",
            "minimum": 2
          }
        }
      }
    }
  }
}
```

### Usage 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",
  "spreadsheet_id": "1abc...",
  "sheet_name": "Leads",
  "source_range": "A1:D20",
  "destination_range": "F1:I20",
  "paste_type": "PASTE_NORMAL"
}
```

```json
{
  "action": "cut_paste",
  "spreadsheet_id": "1abc...",
  "sheet_name": "Leads",
  "source_range": "A1:D20",
  "destination_range": "F1"
}
```

## Other Actions

All actions below require `spreadsheet_id` except `create`, `search`, and
`get_instructions`. `sheet_name` is optional unless stated otherwise; use
`list_sheets` to discover its exact value. These examples omit the connected
account, which the platform supplies.

- `get_instructions`: no fields. `{"action":"get_instructions"}`
- `create`: `title` required; optional `initial_sheet_name`, `initial_headers`.
  `{"action":"create","title":"Weekly Posts","initial_sheet_name":"Posts","initial_headers":["post","status"]}`
- `search`: optional `query`, `max_results` (1-100).
  `{"action":"search","query":"Weekly Posts"}`
- `list_sheets`: `{"action":"list_sheets","spreadsheet_id":"1abc..."}`
- `get_headers`: optional `sheet_name`, `header_row` (default 1).
  `{"action":"get_headers","spreadsheet_id":"1abc...","sheet_name":"Posts"}`
- `get_data_range`: optional `sheet_name`, `range`; a partial range returns no
  append recommendation.
  `{"action":"get_data_range","spreadsheet_id":"1abc...","sheet_name":"Posts"}`
- `add_sheet`: `new_sheet_name` required.
  `{"action":"add_sheet","spreadsheet_id":"1abc...","new_sheet_name":"archive"}`
- `delete_sheet`: one of `sheet_name`, `sheet_id`, `sheet_index` required;
  permanently removes the whole tab.
  `{"action":"delete_sheet","spreadsheet_id":"1abc...","sheet_name":"Old Drafts"}`
- `rename_sheet`: one tab selector and `new_sheet_name` required.
  `{"action":"rename_sheet","spreadsheet_id":"1abc...","sheet_name":"Drafts","new_sheet_name":"Queue"}`
- `sort`: `range` and `sort_specs` required; use an explicit header and order.
  `{"action":"sort","spreadsheet_id":"1abc...","sheet_name":"Posts","range":"A2:I50","sort_specs":[{"header":"status","order":"ASCENDING"}]}`
- `find_replace`: `find` and `replacement` required; add `sheet_name` to
  restrict the change to one tab.
  `{"action":"find_replace","spreadsheet_id":"1abc...","sheet_name":"Posts","find":"draft","replacement":"queued"}`
- `share`: `role` defaults to `reader`; for a person, `email` is required.
  `{"action":"share","spreadsheet_id":"1abc...","email":"editor@example.com","role":"writer"}`

## Safety Guarantees

- `append_rows` never asks the agent to calculate an insertion point.
- `append_column` always appends one new column after the last non-empty data column.
- `update_row` touches only the named cells in `updates`.
- Specific-sheet CSV/TSV exports are generated from Sheets values with proper CSV quoting.
- Specific-sheet rendered exports use the official temporary-spreadsheet flow, not browser `gid` export URLs.
- Expected caller errors such as unknown sheet, duplicate headers, missing key row, or ambiguous row matches return safe messages without operator paging.

## What Not To Do

- Do not use removed low-level action names.
- Do not guess a tab is named `"Sheet1"`; omit `sheet_name` or call `list_sheets`.
- Do not calculate raw append row numbers for table inserts; use `append_rows`.
- Do not calculate raw append column indexes; use `append_column`.
- Do not update an entire row when only a few fields changed; use `update_row`.
- Do not use browser export URLs or `gid` URL parameters for exports; use `export_sheet`.

### Frequently Asked Questions

#### How do I connect this tool to an external agent?

- Page URL: https://www.agentpmt.com/faq
- Markdown URL: https://www.agentpmt.com/faq?format=agent-md

You can install the local MCP server by opening a terminal and running:

```
npm install -g @agentpmt/mcp-router
agentpmt-setup
```

This will connect you to local agents like Claude Code, Windsurf, Grok Build, Cursor, etc.

Alternatively you can connect to the hosted version with this config block, no installation required:

```
{
  "mcpServers": {
    "agentpmt": {
      "type": "streamable-http",
      "url": "https://api.agentpmt.com/mcp",
      "headers": {
        "Authorization": "Bearer <AGENTPMT_BEARER_TOKEN>",
        "x-instance-metadata": "{\"client\":\"generic-mcp\",\"platform\":\"remote\"}"
      }
    }
  }
}
```

[View MCP Connection Instructions](/docs/mcp-reference/connection) for more details.

#### How does an external agent use this tool?

- Page URL: https://www.agentpmt.com/faq
- Markdown URL: https://www.agentpmt.com/faq?format=agent-md

After the external agent is connected to an Agent Group that can use this tool, paste this prompt into the agent:

> Use the AgentPMT-Tool-Search-and-Execution tool. First call action 'get\_instructions' so you know how to use the tool search interface. Then call action 'get\_schema' with tool\_id 696302894cf4309309cac7b2 ("Google Sheets"). After reading the schema and any returned instructions, tell me what this tool can do, we are going to be using it

The agent should fetch the tool schema first, collect the required parameters for your request, and then call the tool through AgentPMT.

### Dependencies

This product has no public dependency products.