# Autosheet API - **OpenAPI Version:** `3.1.0` - **API Version:** `1.0.0` > **Preview** — The Autosheet API is in preview and may change. If you run into issues, contact [GPT for Work support](https://gptforwork.com/support). Use the Autosheet API to run a **spreadsheet agent** programmatically — perform AI-driven enrichment, analysis, edits, and transformations across spreadsheets from your AI agent, workflow tool, or code. Autosheet is built on the same agent engine that powers the [Agent in GPT for Sheets](https://gptforwork.com/docs/gpt-for-sheets/agent). ## Get started To start using the Autosheet API: 1. **Sign in to the [GPT for Work dashboard](https://dashboard.gptforwork.com) with your Google account.** > **Note** — Make sure your space has [credits remaining](#description/credits). 2. **Authorize GPT for Sheets.** In the dashboard sidebar, select **Autosheet API > API keys**. If you see **Connect to Google**, click it and follow the on-screen prompts to authorize GPT for Sheets. 3. **Create an API key.** Enter a descriptive name for the key, click **Create**, and copy the generated key — it will not be shown again. 4. [**Make a copy of our sample spreadsheet.**](https://docs.google.com/spreadsheets/d/1mGKj92RmNEm_FeZudRs6ExBFMTdlvTWtwC38rhUMC0I/copy) Copy the spreadsheet ID — the text string between `/d/` and `/edit` in the URL. 5. **Run your first task.** Open your terminal and enter the following command — with your API key and spreadsheet ID filled in. ```curl curl https://api.autosheet.com/v1/sheets/agents \ --request POST \ --header 'Content-Type: application/json' \ --header 'X-API-Key: ' \ --data '{ "spreadsheet_id": "", "prompt": "Score these leads against our scoring rules." }' ``` In the API response, the top-level `id` field is the agent ID. Copy it for later. 6. **Watch the agent work.** Open the sample spreadsheet and wait for the agent to finish. 7. **(Optional) Check the agent's status.** If you want to poll the agent while it's working on your request, enter the following command in your terminal — with the agent ID and your API key filled in. ```curl curl https://api.autosheet.com/v1/sheets/agents/ \ --header 'X-API-Key: ' ``` The agent has finished when, in the response, the top-level `status` returns to `idle` and `error_message` is `null`. Read the agent's replies from the ordered `messages` array (the last `assistant_message` entry is its final answer). ## Use with a coding agent If you want a coding agent (such as Claude Code, Codex, or Cursor) to scaffold a small script against this API, paste the prompt below into your agent. The prompt primes the agent on the API and asks it to build a script that submits a task, polls for progress, and prints the result. ```markdown # Get started with the Autosheet API **What this is:** A starter prompt to drop into an AI coding agent (such as Claude Code, Codex, or Cursor) so it builds you a small script that runs an Autosheet task against your Google Sheet. **You'll need:** An Autosheet API key, the URL of a Google Sheet, and a prompt describing what you want done. The agent will ask for whatever's missing. ## Get your API key If `$AUTOSHEET_API_KEY` is already set in your environment, the agent will pick it up. Otherwise, get one from the GPT for Work dashboard at https://dashboard.gptforwork.com — sign in with Google, authorize Sheets access on the **Autosheet API** page, click **Create API key**, and copy the key (it's shown only once). ## What you can do Anything Autosheet can do on a sheet — enrich rows, fill columns, dedupe, translate, score. A few examples: - "Fill CEO, headcount, recent news and fit score for every company in column A." - "For each product, write a 50-word description and translate it to French." - "Dedupe these contacts by company; merge 'Acme Inc.' and 'ACME, Inc' into one row." - "Score these leads against our scoring rules." ## API reference - **Base URL:** `https://api.autosheet.com` - **Auth:** send your API key as the `X-API-Key` header on every request - **Verify key:** `GET /v1/auth/verify` - **Submit task:** `POST /v1/sheets/agents` with body `{"spreadsheet_id": "...", "prompt": "..."}` - **Poll status:** `GET /v1/sheets/agents/{id}` — done when `status` is `idle` (`error_message` is `null` on success); `messages` holds the latest turn's ordered messages, its last `assistant_message` entry being the agent's final answer - **Full history:** `GET /v1/sheets/agents/{id}/messages` — the whole conversation, cursor-paginated (`limit`, `after`) - **Cancel task:** `POST /v1/sheets/agents/{id}/stop` Full reference: - Interactive docs → https://autosheet.com/docs/api - OpenAPI spec → https://autosheet.com/docs/api/openapi.yaml --- **Now:** build a small script that submits a task, polls for progress until the agent finishes, and prints the link to the edited Google Sheet when it finishes. Ask me for the API key (only if it's not in the env), the Google Sheet URL, and the prompt. Use whatever language and HTTP client makes sense. ``` ## Authentication All endpoints require an API key in the `X-API-Key` header. API keys are scoped to your user account and inherit your Google Sheets authorization. - Keys can be created, disabled, and deleted from the [GPT for Work dashboard](https://dashboard.gptforwork.com). - A disabled or deleted key will immediately return `401`. - Use the [Verify API Key](#tag/authentication/GET/v1/auth/verify) endpoint to test your key. ## Credits Agents consume credits from your [GPT for Work space](https://gptforwork.com/docs/resources/guides/concepts#space). To run an agent, your space must have credits remaining. Check your available credits in the **Remaining credits** section of the [GPT for Work dashboard](https://dashboard.gptforwork.com), and [buy credits](https://gptforwork.com/docs/admin/billing/buy-credits) whenever you need to top up. ## Polling Use [Get agent](#tag/agents/GET/v1/{platform}/agents/{id}) to check an agent's progress and inspect its work. Pass the agent ID returned when you started the task: ```curl curl https://api.autosheet.com/v1/sheets/agents/ \ --header 'X-API-Key: ' ``` **Reading the result** — the response's `messages` field holds the latest turn's messages as one ordered, type-tagged array (`user_message`, `assistant_message`, `tool_call`), so you never have to merge or reorder anything. The full conversation across all turns is available from [Get agent messages](#tag/agents/GET/v1/{platform}/agents/{id}/messages) (cursor-paginated). Each `tool_call` entry embeds its result summary (`status`, affected `range`, row counters, `completed_at`, and for web\_search the `query`/`number_of_searches`/`sources`) and updates in place as the call completes. **Done condition** — the agent has finished when the top-level `status` returns to `idle`. On success `error_message` is `null`. When the turn failed or was interrupted, `error_message` carries the reason; a cancelled turn may include one (set when you call Stop agent). **Polling frequency** — poll only as often as your workflow needs. API requests are limited to 500 requests per minute per API key. For longer-running tasks, provide a `webhook_url` when [running an agent](#tag/agents/POST/v1/{platform}/agents) and let the webhook notify you on completion instead — see the *Webhooks* section. ## Limits and errors **Request rate limit** — 500 requests/minute per API key. Exceeded requests return `429` with `X-RateLimit-*` and `Retry-After` headers (see the `429` response on [`POST /v1/{platform}/agents`](#tag/agents/POST/v1/{platform}/agents)). **Concurrency limit** — up to 100 active agents per API key. Additional requests return `429`; these responses do not include `Retry-After`, so retry after an active agent finishes. **Spending limits** — Agents consume credits from your [GPT for Work space](https://gptforwork.com/docs/resources/guides/concepts#space). You can set space-wide and user-specific spending limits in the [GPT for Work dashboard](https://dashboard.gptforwork.com). When a limit is reached, new agent requests will be rejected with a `429` response. ## Servers - **URL:** `https://api.autosheet.com` - **Description:** Production ## Operations ### Verify API key - **Method:** `GET` - **Path:** `/v1/auth/verify` - **Tags:** Authentication Validates the provided API key and returns basic account information. Use this endpoint to confirm your key is active and your Google account is connected. #### Responses ##### Status: 200 API key is valid ###### Content-Type: application/json - **`google_connected`** `boolean` — Whether Google Sheets access has been authorized - **`space`** `object` - **`id`** `string`, format: `uuid` — Space ID the key belongs to - **`name`** `string` — Space name - **`user`** `object` - **`email`** `string`, format: `email` — Email associated with the API key owner - **`valid`** `boolean` — Whether the API key is valid and active - **`webhook_secret`** `string | null` — HMAC signing secret for webhook callbacks, or \`null\` if this key has no secret. Use it to verify the \`X-Webhook-Signature\` header on incoming webhook requests — see the \*Webhooks\* section. **Example:** ```json { "valid": true, "user": { "email": "" }, "space": { "id": "", "name": "" }, "google_connected": true, "webhook_secret": null } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ### Start agent - **Method:** `POST` - **Path:** `/v1/{platform}/agents` - **Tags:** Agents Creates a new agent or adds a follow-up prompt to an existing agent. **New agent** — provide `spreadsheet_id` and `prompt`. A new agent is created and starts processing automatically. **Follow-up** — also provide `agent_id` to continue a previous agent's conversation. The agent must be in `idle` status (all previous turns completed). **Webhook** — optionally provide a `webhook_url` to receive a `POST` callback when the turn completes. See the *Webhooks* section for the payload and signature contract. #### Parameters ##### `platform` required - **In:** `path` Target platform `string`, possible values: `"sheets"` #### Request Body ##### Content-Type: application/json - **`prompt` (required)** `string` — Natural language instruction for the agent to execute - **`agent_id`** `string`, format: `uuid` — ID of an existing agent to continue. When provided, the prompt is added as a follow-up turn. The agent must be in \`idle\` status. If omitted, a new agent is created and \`spreadsheet\_id\` becomes required. - **`agent_model`** `string` — Override the default agent model. Use an \`id\` from the \`models.agent\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default agent model is used. - **`bulk_model`** `string` — Override the default bulk tool model. Use an \`id\` from the \`models.bulk\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default bulk model is used. - **`bulk_search_model`** `string` — Override the default web search model. Use an \`id\` from the \`models.bulk\_search\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default search model is used. - **`sheet_name`** `string` — Name of the sheet to operate on. Defaults to the first sheet (new agent) or the sheet from the previous turn (follow-up). - **`spreadsheet_id`** `string` — Google Sheets spreadsheet ID (found in the spreadsheet URL between \`/d/\` and \`/edit\`). \*\*Required\*\* when creating a new agent (no \`agent\_id\`). Silently ignored on follow-ups. - **`webhook_url`** `string`, format: `uri` — Optional URL to receive a \`POST\` callback when the turn completes. See the \*Webhooks\* section for the payload and signature contract. **Example:** ```json { "agent_id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "", "prompt": "Translate all content in column B from French to English", "sheet_name": "Sheet1", "agent_model": "managed:agent:anthropic/claude-opus-4-6", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar", "webhook_url": "https://example.com/webhooks/autosheet" } ``` #### Responses ##### Status: 201 Agent created or follow-up turn added ###### Content-Type: application/json - **`created_at` (required)** `string`, format: `date-time` — When the agent was created - **`error_message` (required)** `string | null` — The latest turn's error message (failure reason), or \`null\` when it has not errored. \`null\` while the turn is still in progress (\`status: active\`). Always returned — errored turns produce no assistant message, so this is where failures surface. - **`id` (required)** `string`, format: `uuid` — Unique agent identifier - **`last_activity_at` (required)** `string | null`, format: `date-time` — When the agent last had activity - **`messages` (required)** `array` — The latest turn's messages as a single ordered, type-tagged array. Always returned. The full conversation across all turns is served (paginated) by \`GET /v1/{platform}/agents/{id}/messages\`. **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. - **`models` (required)** `object` — The effective models for this agent (the most recent turn's), or \`null\`. Always returned. - **`number_of_turns` (required)** `integer` — Total number of turns in this agent's conversation, including the one in progress when the agent is \`active\`. - **`spreadsheet_id` (required)** `string` — Google Sheets spreadsheet ID - **`status` (required)** `string`, possible values: `"active", "idle"` — Agent status: - \`active\`: A turn is currently in progress - \`idle\`: All turns are completed **Example:** ```json { "id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms", "status": "active", "created_at": "", "last_activity_at": null, "number_of_turns": 3, "models": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" }, "error_message": null, "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ] } ``` ##### Status: 400 Invalid request parameters ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 403 The request is well-formed and authenticated but cannot be served: either no Google account is connected to this API key, or the connected Google account does not have access to the spreadsheet. ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 404 The spreadsheet does not exist (well-formed but unknown ID). ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 409 Agent is still processing a previous turn (follow-up only) ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 429 Rate limit exceeded ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 502 An upstream dependency returned an invalid response while serving the request. The API gateway is healthy; the fault is upstream. Safe to retry with backoff — no agent was created. ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 504 The request timed out waiting on an upstream dependency. Safe to retry with backoff — the agent may or may not have started, so prefer an idempotent retry or check status before re-issuing. ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ### Get agent - **Method:** `GET` - **Path:** `/v1/{platform}/agents/{id}` - **Tags:** Agents Retrieves the current status and conversation of an agent. The response always includes the effective `models`, the latest turn's `error_message`, the total `number_of_turns`, and the latest turn's messages as a single ordered, type-tagged `messages` array. Tool calls carry compact summary details (status, affected range, row counters, and other per-tool fields — see the `AgentToolCall` schema) rather than full payloads. For the full conversation across all turns, use [Get agent messages](#tag/agents/GET/v1/{platform}/agents/{id}/messages). #### Parameters ##### `platform` required - **In:** `path` Target platform `string`, possible values: `"sheets"` ##### `id` required - **In:** `path` Agent ID (UUID) `string`, format: `uuid` #### Responses ##### Status: 200 Agent details ###### Content-Type: application/json - **`created_at` (required)** `string`, format: `date-time` — When the agent was created - **`error_message` (required)** `string | null` — The latest turn's error message (failure reason), or \`null\` when it has not errored. \`null\` while the turn is still in progress (\`status: active\`). Always returned — errored turns produce no assistant message, so this is where failures surface. - **`id` (required)** `string`, format: `uuid` — Unique agent identifier - **`last_activity_at` (required)** `string | null`, format: `date-time` — When the agent last had activity - **`messages` (required)** `array` — The latest turn's messages as a single ordered, type-tagged array. Always returned. The full conversation across all turns is served (paginated) by \`GET /v1/{platform}/agents/{id}/messages\`. **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. - **`models` (required)** `object` — The effective models for this agent (the most recent turn's), or \`null\`. Always returned. - **`number_of_turns` (required)** `integer` — Total number of turns in this agent's conversation, including the one in progress when the agent is \`active\`. - **`spreadsheet_id` (required)** `string` — Google Sheets spreadsheet ID - **`status` (required)** `string`, possible values: `"active", "idle"` — Agent status: - \`active\`: A turn is currently in progress - \`idle\`: All turns are completed **Example:** ```json { "id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms", "status": "active", "created_at": "", "last_activity_at": null, "number_of_turns": 3, "models": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" }, "error_message": null, "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ] } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 404 Agent not found ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ### Get agent messages - **Method:** `GET` - **Path:** `/v1/{platform}/agents/{id}/messages` - **Tags:** Agents Retrieves the full conversation across all of the agent's turns as a single ordered, type-tagged array, paginated with a cursor. Pass `limit` to control the page size and the returned `end_cursor` as `after` to fetch the next page; `has_next_page` tells you when to stop. Entries are returned oldest-first. #### Parameters ##### `platform` required - **In:** `path` Target platform `string`, possible values: `"sheets"` ##### `id` required - **In:** `path` Agent ID (UUID) `string`, format: `uuid` ##### `limit` - **In:** `query` Page size, 1–100. `integer`, default: `20` ##### `after` - **In:** `query` Cursor returned as `end_cursor` by a previous page; entries strictly after it are returned. Omit it to fetch the first page. `string` #### Responses ##### Status: 200 One page of conversation entries ###### Content-Type: application/json - **`end_cursor` (required)** `string | null` — Cursor of the last entry on this page — pass as \`after\` to fetch the next page. Populated on every non-empty page, including the last one (where \`has\_next\_page\` is \`false\`); \`null\` only when the page is empty. Use \`has\_next\_page\`, not this field, to decide whether to keep paginating. - **`has_next_page` (required)** `boolean` - **`messages` (required)** `array` **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. - **`total` (required)** `integer` — Total number of entries in the full conversation. **Example:** ```json { "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ], "end_cursor": "Xq9k2Lm7Pa0bZ3Rt", "has_next_page": true, "total": 123 } ``` ##### Status: 400 Invalid request parameters ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 404 Agent not found ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ### Stop agent - **Method:** `POST` - **Path:** `/v1/{platform}/agents/{id}/stop` - **Tags:** Agents Stops a running agent. If the agent has an active turn, it will be marked as cancelled. Completed turns are not affected. #### Parameters ##### `platform` required - **In:** `path` Target platform `string`, possible values: `"sheets"` ##### `id` required - **In:** `path` Agent ID (UUID) `string`, format: `uuid` #### Responses ##### Status: 200 Agent stopped ###### Content-Type: application/json - **`created_at` (required)** `string`, format: `date-time` — When the agent was created - **`error_message` (required)** `string | null` — The latest turn's error message (failure reason), or \`null\` when it has not errored. \`null\` while the turn is still in progress (\`status: active\`). Always returned — errored turns produce no assistant message, so this is where failures surface. - **`id` (required)** `string`, format: `uuid` — Unique agent identifier - **`last_activity_at` (required)** `string | null`, format: `date-time` — When the agent last had activity - **`messages` (required)** `array` — The latest turn's messages as a single ordered, type-tagged array. Always returned. The full conversation across all turns is served (paginated) by \`GET /v1/{platform}/agents/{id}/messages\`. **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. - **`models` (required)** `object` — The effective models for this agent (the most recent turn's), or \`null\`. Always returned. - **`number_of_turns` (required)** `integer` — Total number of turns in this agent's conversation, including the one in progress when the agent is \`active\`. - **`spreadsheet_id` (required)** `string` — Google Sheets spreadsheet ID - **`status` (required)** `string`, possible values: `"active", "idle"` — Agent status: - \`active\`: A turn is currently in progress - \`idle\`: All turns are completed **Example:** ```json { "id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms", "status": "active", "created_at": "", "last_activity_at": null, "number_of_turns": 3, "models": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" }, "error_message": null, "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ] } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 404 Agent not found ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ### List available models - **Method:** `GET` - **Path:** `/v1/{platform}/agents/configuration` - **Tags:** Agents Returns the available models for your space, grouped by purpose. If your space has custom model settings, those are returned. Otherwise, platform defaults are used. Use the model `id` values when creating an agent with a specific model override. #### Parameters ##### `platform` required - **In:** `path` Target platform `string`, possible values: `"sheets"` #### Responses ##### Status: 200 Available configuration ###### Content-Type: application/json - **`models`** `object` — Available models and current defaults for this space - **`agent_models`** `array` — Models available for agent execution. Use the \`id\` in the \`agent\_model\` field when running an agent. **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`bulk_models`** `array` — Models available for bulk (standard) operations **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`bulk_search_models`** `array` — Models available for web search operations **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`defaults`** `object` — Current default model selections for this space - **`agent_model`** `string` — Default agent model ID - **`bulk_model`** `string` — Default bulk model ID - **`bulk_search_model`** `string` — Default web search model ID **Example:** ```json { "models": { "agent_models": [ { "id": "managed:agent:openai/gpt-5.1", "label": "gpt-5.1", "provider": "openai", "is_default": true }, { "id": "managed:agent:anthropic/claude-opus-4-6", "label": "claude-opus-4-6", "provider": "anthropic", "is_default": false } ], "bulk_models": [ { "id": "managed:bulk:openai/gpt-4.1", "label": "gpt-4.1", "provider": "openai", "is_default": true } ], "bulk_search_models": [ { "id": "managed:search:perplexity/sonar", "label": "sonar", "provider": "perplexity", "is_default": true } ], "defaults": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" } } } ``` ##### Status: 401 Invalid or missing API key ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ``` ## Webhooks ### Turn completed - **Method:**`POST` - **Path:**`/webhooks/turnCompleted` - **Tags:** Webhooks Provide a `webhook_url` when [running an agent](#tag/agents/POST/v1/{platform}/agents) and Autosheet sends this `POST` callback once the turn completes — so you don't have to poll. The callback fires for every outcome, with the `status` field set to `succeeded`, `failed`, `interrupted`, or `cancelled`. **Signature verification** — each request carries `X-Webhook-Signature: sha256=`, an HMAC-SHA256 of the **raw request body** keyed with your webhook secret. Fetch the secret from the [Verify API Key](#tag/authentication/GET/v1/auth/verify) response (`webhook_secret` field), re-compute the HMAC over the raw body, and compare using a constant-time check (`crypto.timingSafeEqual` in Node, `hmac.compare_digest` in Python). Reject the request on mismatch. **Delivery** — respond with any `2xx` status to acknowledge. Non-`2xx` responses are not retried. ## Schemas ### VerifyApiKeyResponse - **Type:**`object` * **`google_connected`** `boolean` — Whether Google Sheets access has been authorized * **`space`** `object` - **`id`** `string`, format: `uuid` — Space ID the key belongs to - **`name`** `string` — Space name * **`user`** `object` - **`email`** `string`, format: `email` — Email associated with the API key owner * **`valid`** `boolean` — Whether the API key is valid and active * **`webhook_secret`** `string | null` — HMAC signing secret for webhook callbacks, or \`null\` if this key has no secret. Use it to verify the \`X-Webhook-Signature\` header on incoming webhook requests — see the \*Webhooks\* section. **Example:** ```json { "valid": true, "user": { "email": "" }, "space": { "id": "", "name": "" }, "google_connected": true, "webhook_secret": null } ``` ### ConfigurationResponse - **Type:**`object` * **`models`** `object` — Available models and current defaults for this space - **`agent_models`** `array` — Models available for agent execution. Use the \`id\` in the \`agent\_model\` field when running an agent. **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`bulk_models`** `array` — Models available for bulk (standard) operations **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`bulk_search_models`** `array` — Models available for web search operations **Items:** - **`id`** `string` — Model identifier to use in API requests - **`is_default`** `boolean` — Whether this is the current default for its category - **`label`** `string` — Human-readable model name - **`provider`** `string` — Model provider - **`defaults`** `object` — Current default model selections for this space - **`agent_model`** `string` — Default agent model ID - **`bulk_model`** `string` — Default bulk model ID - **`bulk_search_model`** `string` — Default web search model ID **Example:** ```json { "models": { "agent_models": [ { "id": "managed:agent:openai/gpt-5.1", "label": "gpt-5.1", "provider": "openai", "is_default": true }, { "id": "managed:agent:anthropic/claude-opus-4-6", "label": "claude-opus-4-6", "provider": "anthropic", "is_default": false } ], "bulk_models": [ { "id": "managed:bulk:openai/gpt-4.1", "label": "gpt-4.1", "provider": "openai", "is_default": true } ], "bulk_search_models": [ { "id": "managed:search:perplexity/sonar", "label": "sonar", "provider": "perplexity", "is_default": true } ], "defaults": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" } } } ``` ### ModelOption - **Type:**`object` * **`id`** `string` — Model identifier to use in API requests * **`is_default`** `boolean` — Whether this is the current default for its category * **`label`** `string` — Human-readable model name * **`provider`** `string` — Model provider **Example:** ```json { "id": "managed:agent:openai/gpt-5.1", "label": "gpt-5.1", "provider": "openai", "is_default": true } ``` ### WebhookPayload - **Type:**`object` Body of the `POST` callback Autosheet sends to your `webhook_url` when a turn completes. - **`agent_id` (required)** `string`, format: `uuid` — The agent that was running - **`error_message` (required)** `string | null` — Error details when status is \`failed\` or \`interrupted\`, otherwise \`null\` - **`status` (required)** `string`, possible values: `"succeeded", "failed", "interrupted", "cancelled"` — Turn outcome. \`succeeded\` means the turn reached its natural end — inspect the conversation for the result quality. - **`turn_id` (required)** `string`, format: `uuid` — The specific turn that completed **Example:** ```json { "agent_id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "turn_id": "a3c2e8d1-4b56-4f89-9012-def456789abc", "status": "succeeded", "error_message": null } ``` ### RunAgentRequest - **Type:**`object` * **`prompt` (required)** `string` — Natural language instruction for the agent to execute * **`agent_id`** `string`, format: `uuid` — ID of an existing agent to continue. When provided, the prompt is added as a follow-up turn. The agent must be in \`idle\` status. If omitted, a new agent is created and \`spreadsheet\_id\` becomes required. * **`agent_model`** `string` — Override the default agent model. Use an \`id\` from the \`models.agent\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default agent model is used. * **`bulk_model`** `string` — Override the default bulk tool model. Use an \`id\` from the \`models.bulk\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default bulk model is used. * **`bulk_search_model`** `string` — Override the default web search model. Use an \`id\` from the \`models.bulk\_search\_models\` list in \[List available models]\(#tag/agents/GET/v1/{platform}/agents/configuration). If not specified, the space's default search model is used. * **`sheet_name`** `string` — Name of the sheet to operate on. Defaults to the first sheet (new agent) or the sheet from the previous turn (follow-up). * **`spreadsheet_id`** `string` — Google Sheets spreadsheet ID (found in the spreadsheet URL between \`/d/\` and \`/edit\`). \*\*Required\*\* when creating a new agent (no \`agent\_id\`). Silently ignored on follow-ups. * **`webhook_url`** `string`, format: `uri` — Optional URL to receive a \`POST\` callback when the turn completes. See the \*Webhooks\* section for the payload and signature contract. **Example:** ```json { "agent_id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "", "prompt": "Translate all content in column B from French to English", "sheet_name": "Sheet1", "agent_model": "managed:agent:anthropic/claude-opus-4-6", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar", "webhook_url": "https://example.com/webhooks/autosheet" } ``` ### Agent - **Type:**`object` * **`created_at` (required)** `string`, format: `date-time` — When the agent was created * **`error_message` (required)** `string | null` — The latest turn's error message (failure reason), or \`null\` when it has not errored. \`null\` while the turn is still in progress (\`status: active\`). Always returned — errored turns produce no assistant message, so this is where failures surface. * **`id` (required)** `string`, format: `uuid` — Unique agent identifier * **`last_activity_at` (required)** `string | null`, format: `date-time` — When the agent last had activity * **`messages` (required)** `array` — The latest turn's messages as a single ordered, type-tagged array. Always returned. The full conversation across all turns is served (paginated) by \`GET /v1/{platform}/agents/{id}/messages\`. **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. * **`models` (required)** `object` — The effective models for this agent (the most recent turn's), or \`null\`. Always returned. * **`number_of_turns` (required)** `integer` — Total number of turns in this agent's conversation, including the one in progress when the agent is \`active\`. * **`spreadsheet_id` (required)** `string` — Google Sheets spreadsheet ID * **`status` (required)** `string`, possible values: `"active", "idle"` — Agent status: - \`active\`: A turn is currently in progress - \`idle\`: All turns are completed **Example:** ```json { "id": "1f7b5f98-3906-40f4-b177-8bc2327df6f1", "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms", "status": "active", "created_at": "", "last_activity_at": null, "number_of_turns": 3, "models": { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" }, "error_message": null, "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ] } ``` ### AgentModels - **Type:**`object` Models used by the agent. Each turn can use different models if overridden in the request. - **`agent_model`** `string` — Agent model in effect - **`bulk_model`** `string` — Bulk tool model in effect - **`bulk_search_model`** `string` — Web search model in effect **Example:** ```json { "agent_model": "managed:agent:openai/gpt-5.1", "bulk_model": "managed:bulk:openai/gpt-4.1", "bulk_search_model": "managed:search:perplexity/sonar" } ``` ### AgentStatus - **Type:**`string` Agent status: - `active`: A turn is currently in progress - `idle`: All turns are completed **Example:** ### AgentToolCall - **Type:**`object` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. **Example:** ```json { "tool_call_id": "", "created_at": "", "completed_at": null, "tool": "write_range", "status": "pending", "range": "A1:A40", "sheet_name": "Sheet1", "source_range": "A1:A5", "target_range": "C1:C5", "paste_type": "PASTE_VALUES_ONLY", "fields": "sheets(properties(sheetId,title))", "query": "height of Mount Everest in meters", "number_of_searches": 2, "sources": [ "https://en.wikipedia.org/wiki/Mount_Everest", "https://britannica.com/place/Mount-Everest" ], "skill": "charts", "updated_range": "B1:B5", "prompt_template": "Convert the number in {{A}} to its English word form.", "rows": { "processed": 1, "errors": 1, "total": 1 }, "message": "" } ``` ### MessageEntry - **Type:** One entry in the ordered conversation `messages` array. The `type` field discriminates between the variants. **Example:** ### AgentMessagesPage - **Type:**`object` One page of the full conversation, oldest-first. - **`end_cursor` (required)** `string | null` — Cursor of the last entry on this page — pass as \`after\` to fetch the next page. Populated on every non-empty page, including the last one (where \`has\_next\_page\` is \`false\`); \`null\` only when the page is empty. Use \`has\_next\_page\`, not this field, to decide whether to keep paginating. - **`has_next_page` (required)** `boolean` - **`messages` (required)** `array` **Items:** **One of:** - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` * **`content` (required)** `string` * **`created_at` (required)** `string`, format: `date-time` * **`message_id` (required)** `string`, format: `uuid` * **`turn_id` (required)** `string`, format: `uuid` * **`type` (required)** `string`, possible values: `"assistant_message"` **All of:** - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"tool_call"` * **`created_at` (required)** `string`, format: `date-time` — When the tool call started. * **`status` (required)** `string`, possible values: `"pending", "running", "completed", "error", "succeeded", "failed", "cancelled"` — Bulk tools report \`succeeded\` (all rows processed without failures) or \`failed\`; other tools report \`completed\` or \`error\`. A call the user cancelled mid-turn reports \`cancelled\`. * **`tool` (required)** `string` — Name of the tool that was called * **`tool_call_id` (required)** `string`, format: `uuid` — Tool-call identifier. * **`completed_at`** `string | null`, format: `date-time` — When the tool call reached a terminal status, or \`null\` while it is still \`pending\`/\`running\`. * **`fields`** `string` — read\_spreadsheet\_fields: the requested field mask. * **`message`** `string` — Result message from the tool call. Only present when the call errored (carries the failure reason). * **`number_of_searches`** `integer` — web\_search: how many searches the tool ran. Each is a billed unit. * **`paste_type`** `string` — copy\_paste\_range: the paste behaviour. * **`prompt_template`** `string` — Bulk tools: the per-row prompt template (column refs as \`{{A}}\`). * **`query`** `string` — web\_search: the query searched for (the tool's prompt). * **`range`** `string` — Affected range, without sheet prefix (see \`sheet\_name\`). Not returned for bulk tools, which use \`updated\_range\`, nor copy\_paste\_range, which uses \`source\_range\`/\`target\_range\`. * **`rows`** `object` — Bulk tools only: row counters. Absent for non-bulk tools. Includes whichever of \`processed\` (successful rows), \`errors\`, and \`total\` the tool reported. - **`errors`** `integer` — Failed rows. - **`processed`** `integer` — Successfully processed rows. - **`total`** `integer` — Total rows to process (successful + failed + never run). * **`sheet_name`** `string` — Sheet the tool operated on (range tools, bulk tools, get\_sheet\_overview, read\_spreadsheet\_fields). * **`skill`** `string` — load\_skill / create\_skill: the skill name(s). * **`source_range`** `string` — copy\_paste\_range: the range copied from. * **`sources`** `array` — web\_search: the pages the model opened and read, plus any URLs it cited, deduplicated. (Not the full set of links the searches surfaced.) **Items:** `string`, format: `uri` * **`target_range`** `string` — copy\_paste\_range: the range pasted into. * **`updated_range`** `string` — Bulk tools: the range actually written. - **`total` (required)** `integer` — Total number of entries in the full conversation. **Example:** ```json { "messages": [ { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ], "end_cursor": "Xq9k2Lm7Pa0bZ3Rt", "has_next_page": true, "total": 123 } ``` ### UserMessageEntry - **Type:**`object` A user message in the conversation. - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` — The turn this entry belongs to (groups entries by prompt execution). - **`type` (required)** `string`, possible values: `"user_message"` **Example:** ```json { "type": "user_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ``` ### AssistantMessageEntry - **Type:**`object` An assistant message (reasoning or final response) in the conversation. - **`content` (required)** `string` - **`created_at` (required)** `string`, format: `date-time` - **`message_id` (required)** `string`, format: `uuid` - **`turn_id` (required)** `string`, format: `uuid` - **`type` (required)** `string`, possible values: `"assistant_message"` **Example:** ```json { "type": "assistant_message", "turn_id": "", "message_id": "", "created_at": "", "content": "" } ``` ### ToolCallEntry - **Type:** A tool call in the conversation, with its result embedded: `status`, `completed_at` and the summary details update in place as the call completes. **Example:** ### Error - **Type:**`object` * **`error`** `object` - **`code` (required)** `string` — Machine-readable error code - **`message` (required)** `string` — Human-readable error message **Example:** ```json { "error": { "code": "", "message": "" } } ```