> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Smartsheet

> Client-mode REST API connector for Smartsheet: append shift, batch and downtime rows from plant events, update row status and readings, keep sheet-summary KPIs current, comment and attach links on rows, request sign-off, archive closed rows, read sheets, reports and dashboards back, and register webhooks to a Coreflux server connector

Technical Preview

## Overview

A client-mode connector for the [Smartsheet API 2.0](https://developers.smartsheet.com/api/smartsheet/introduction) that puts plant data into the sheets operations teams already work in. A typical flow appends a row to a shift log, downtime tracker or quality-check sheet whenever the broker sees an event, updates status and readings on that row as things change, keeps sheet-summary KPIs such as OEE, scrap or uptime current, adds a comment and a dashboard link to the row, asks the shift lead to confirm the cause with an update request, and moves closed rows to an archive sheet. The same connector reads sheets, rows, cell history, reports and dashboards back into the broker, and registers Smartsheet webhooks that post sheet changes to a Coreflux server connector.

One connector carries 44 events (27 GET, 12 POST, 5 PUT; 17 writes, no DELETE). Topics use `devops/smartsheet/<object>/<verb>`; each response is published on `<source topic>/response`.

> [!NOTE]
>
> The template was checked against Smartsheet's [OpenAPI reference](https://developers.smartsheet.com/api/smartsheet/openapi/schemas/index) and a local mock. `ServerInfo` was called live, without a token, on the US, EU and AU hosts. Every event was sent to `api.smartsheet.com` with a dummy token, and each one answered `401` with error code 1002 (invalid token). Without a token, 18 events also showed that Smartsheet connectors their path and method: the real path was refused (401 or 403) while the same path with a bad suffix answered 404. Nothing has run with a real token yet, so status stays blocked until an authenticated read and a row write pass.

## Setup

1. In Smartsheet, open **Account > Apps & Integrations > API Access** and generate an API access token. The token acts as the user who created it, so use a service account (for example `plant-integration@example.com`) that is shared on the sheets you automate. OAuth 2.0 access tokens work the same way.
2. Keep the token in a broker secret (for example `SMARTSHEET_ACCESS_TOKEN`) and inject it in a LoT action with `GET SECRET`. Never retain topics that carry it.
3. Read the sheet once with `SheetGet` or `ColumnsList` to get its column ids. Rows are written by column id, not by column title.

## Authentication

Every event sends `Authorization: Bearer <token>` built from the `access_token` field of the payload:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "YOUR_SMARTSHEET_TOKEN"}
```

`ServerInfo` also works with an empty `access_token`, which makes it a simple reachability check.

## Regions

The template points at `https://api.smartsheet.com` (paths under `/2.0/`). For Smartsheet Regions Europe change `BASE_ADDRESS` to `https://api.smartsheet.eu`; for Smartsheet Regions Australia use `https://api.smartsheet.au`. Each region issues its own tokens, so a token from one region does not work on another.

## Query parameters and bodies

Events that take query parameters read them, already URL-encoded, from `query` (for example `rowsModifiedSince=2026-10-05T06%3A00%3A00Z&level=2`). Leave `query` empty for defaults. Writes send JSON from `body`. Smartsheet ids are 64-bit integers: send them as JSON numbers inside `body`, and as plain digits in path fields such as `sheet` and `row`. Values are sent as given, so URL-encode `query` yourself.

## Examples

Append a downtime row when a press stops (`devops/smartsheet/rows/add`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "<token>", "sheet": "4583173393803140", "query": "allowPartialSuccess=true", "body": [{"toBottom": true, "cells": [{"columnId": 7960873114331012, "value": "Press 7"}, {"columnId": 642523719853956, "value": 94.2}, {"columnId": 5225480965908356, "value": "Open"}]}]}
```

Smartsheet answers with `result`, which holds the new rows and their `id` values. Keep the row id to update the row later.

Close the row when the press restarts (`devops/smartsheet/rows/update`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "<token>", "sheet": "4583173393803140", "query": "", "body": [{"id": 2361756178769796, "cells": [{"columnId": 5225480965908356, "value": "Closed"}]}]}
```

Read only the rows that changed this shift (`devops/smartsheet/sheets/get`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "<token>", "sheet": "4583173393803140", "query": "rowsModifiedSince=2026-10-05T06%3A00%3A00Z&columnIds=7960873114331012,5225480965908356"}
```

Poll `devops/smartsheet/sheets/version/get` first if you only need to know whether anything changed.

Update a KPI in the sheet summary (`devops/smartsheet/sheets/summary/fields/update`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "<token>", "sheet": "4583173393803140", "query": "", "body": [{"id": 101, "objectValue": 87.4}]}
```

Send sheet changes to a Coreflux server connector (`devops/smartsheet/webhooks/create`, then `devops/smartsheet/webhooks/update` with `{"enabled": true}`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "<token>", "body": {"name": "Porto line 2 downtime", "callbackUrl": "https://broker.example.com/smartsheet/events", "scope": "sheet", "scopeObjectId": 4583173393803140, "events": ["*.*"], "version": 1}}
```

> [!WARNING]
>
> New webhooks are created disabled. When you enable one, Smartsheet sends a verification request to `callbackUrl` with a `Smartsheet-Hook-Challenge` header and a `challenge` body field. The receiving server connector must answer `200` and echo the value in a `Smartsheet-Hook-Response` header or a `smartsheetHookResponse` JSON field. Smartsheet repeats this check once every 100 callbacks and disables the webhook (`DISABLED_VERIFICATION_FAILED`) if it fails. Requests come from `webhooks.smartsheet.com`. Callbacks carry only event metadata (object type, ids, event type), so read the changed rows with `RowGet` or `SheetGet`.

Every write event sends `Smartsheet-Change-Agent: coreflux-broker`. Callbacks for changes made through this connector then carry `changeAgent` `coreflux-broker`, so the server connector can skip them and avoid update loops.

## Events

| Event | Method | Endpoint | Source topic | Write | Notes |
| - | - | - | - | - | - |
| `UserMe` | `GET` | `/2.0/users/me?{value.json.query}` | `devops/smartsheet/users/me` | | Smoke: the user who owns the token (id, email, account, locale). query e.g. include=groups (or empty). |
| `ServerInfo` | `GET` | `/2.0/serverinfo` | `devops/smartsheet/server-info/get` | | Application constants (formats, locales, server version). Works with an empty access\_token: a reachability check for the region host. |
| `UsersList` | `GET` | `/2.0/users?{value.json.query}` | `devops/smartsheet/users/list` | | Users in the organization (ids and emails for update requests and assignments). query e.g. email=tech%40example.com or page=1\&pageSize=100. |
| `SheetsList` | `GET` | `/2.0/sheets?{value.json.query}` | `devops/smartsheet/sheets/list` | | Sheets the token can see. query e.g. modifiedSince=2026-10-01T00:00:00Z\&pageSize=100\&page=1 (or includeAll=true). |
| `SheetGet` | `GET` | `/2.0/sheets/{value.json.sheet}?{value.json.query}` | `devops/smartsheet/sheets/get` | | Catalog 'GET sheets/\{id}'. Sheet with columns and rows. query e.g. rowsModifiedSince=2026-10-05T06:00:00Z\&columnIds=\<id>,\<id>\&level=2\&include=objectValue (or rowIds=..., filterId=..., ifVersionAfter=\<version>). |
| `SheetVersionGet` | `GET` | `/2.0/sheets/{value.json.sheet}/version` | `devops/smartsheet/sheets/version/get` | | Sheet version only: a cheap poll to see whether anything changed before calling SheetGet. |
| `SheetUpdate` | `PUT` | `/2.0/sheets/{value.json.sheet}` | `devops/smartsheet/sheets/update` | Yes | Rename a sheet or change its settings. body: \{"name":"Line 2 shift log 2026-W41"}. |
| `SheetCreateInWorkspace` | `POST` | `/2.0/workspaces/{value.json.workspace}/sheets?{value.json.query}` | `devops/smartsheet/sheets/create-in-workspace` | Yes | Create a sheet in a workspace (or a copy of a template with fromId). body: \{"name":"Porto line 2 downtime","columns":\[\{"title":"Asset","primary":true,"type":"TEXT\_NUMBER"},\{"title":"Minutes","type":"TEXT\_NUMBER"},\{"title":"Status","type":"PICKLIST","options":\["Open","Closed"]}]}. query e.g. include=attachments (or empty). |
| `SheetCreateInFolder` | `POST` | `/2.0/folders/{value.json.folder}/sheets?{value.json.query}` | `devops/smartsheet/sheets/create-in-folder` | Yes | Create a sheet in a folder. Same body as SheetCreateInWorkspace. query e.g. include=data (or empty). |
| `SheetCopy` | `POST` | `/2.0/sheets/{value.json.sheet}/copy?{value.json.query}` | `devops/smartsheet/sheets/copy` | Yes | Copy a template sheet, e.g. one per batch or week. body: \{"destinationType":"workspace","destinationId":\<workspaceId>,"newName":"Batch 2026-1005-A"}. query e.g. include=data,discussions (or empty). |
| `SheetSummaryGet` | `GET` | `/2.0/sheets/{value.json.sheet}/summary?{value.json.query}` | `devops/smartsheet/sheets/summary/get` | | Sheet summary fields (ids and current values, e.g. OEE, scrap, uptime). query e.g. include=format (or empty). |
| `SheetSummaryFieldsUpdate` | `PUT` | `/2.0/sheets/{value.json.sheet}/summary/fields?{value.json.query}` | `devops/smartsheet/sheets/summary/fields/update` | Yes | Keep summary KPIs current (OEE, scrap, uptime). body: \[\{"id":\<fieldId>,"objectValue":87.4}] (ids from SheetSummaryGet; objectValue is a string, number or boolean for simple fields). query e.g. renameIfConflict=true (or empty). |
| `ColumnsList` | `GET` | `/2.0/sheets/{value.json.sheet}/columns?{value.json.query}` | `devops/smartsheet/columns/list` | | Columns of a sheet (ids and types for RowsAdd / RowsUpdate). query e.g. includeAll=true (or empty). |
| `ColumnGet` | `GET` | `/2.0/sheets/{value.json.sheet}/columns/{value.json.column}?{value.json.query}` | `devops/smartsheet/columns/get` | | One column. query e.g. level=2 (or empty). |
| `ColumnsAdd` | `POST` | `/2.0/sheets/{value.json.sheet}/columns` | `devops/smartsheet/columns/add` | Yes | Add columns (same index for every column in one call). body: \[\{"title":"Temperature C","type":"TEXT\_NUMBER","index":3}]. |
| `ColumnUpdate` | `PUT` | `/2.0/sheets/{value.json.sheet}/columns/{value.json.column}` | `devops/smartsheet/columns/update` | Yes | Rename a column or change its picklist options. body: \{"title":"Status","type":"PICKLIST","options":\["Open","In progress","Closed"]}. |
| `RowsAdd` | `POST` | `/2.0/sheets/{value.json.sheet}/rows?{value.json.query}` | `devops/smartsheet/rows/add` | Yes | Catalog 'POST sheets/\{id}/rows'. Append one row per event, or a batch. body: \[\{"toBottom":true,"cells":\[\{"columnId":\<id>,"value":"Press 7"},\{"columnId":\<id>,"value":94.2}]}]. query e.g. allowPartialSuccess=true\&overrideValidation=true (or empty). Returns the new row ids. |
| `RowsUpdate` | `PUT` | `/2.0/sheets/{value.json.sheet}/rows?{value.json.query}` | `devops/smartsheet/rows/update` | Yes | Catalog 'PUT sheets/\{id}/rows'. Update cells on existing rows by row id. body: \[\{"id":\<rowId>,"cells":\[\{"columnId":\<id>,"value":"Closed"}]}]. query e.g. allowPartialSuccess=true (or empty). |
| `RowGet` | `GET` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}?{value.json.query}` | `devops/smartsheet/rows/get` | | One row with its cells. query e.g. include=columns,objectValue (or empty). |
| `RowsMove` | `POST` | `/2.0/sheets/{value.json.sheet}/rows/move?{value.json.query}` | `devops/smartsheet/rows/move` | Yes | Move closed rows to an archive sheet (instead of deleting). body: \{"rowIds":\[\<rowId>],"to":\{"sheetId":\<archiveSheetId>}}. query e.g. include=attachments,discussions. |
| `RowsCopy` | `POST` | `/2.0/sheets/{value.json.sheet}/rows/copy?{value.json.query}` | `devops/smartsheet/rows/copy` | Yes | Copy rows to another sheet (e.g. a plant-wide roll-up). body: \{"rowIds":\[\<rowId>],"to":\{"sheetId":\<targetSheetId>}}. query e.g. include=all (or empty). |
| `CellHistoryList` | `GET` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}/columns/{value.json.column}/history?{value.json.query}` | `devops/smartsheet/cells/history/list` | | Change history of one cell (who changed it and when). 30 requests per minute per token. query e.g. pageSize=50 (or empty). |
| `SheetSearch` | `GET` | `/2.0/search/sheets/{value.json.sheet}?{value.json.query}` | `devops/smartsheet/search/sheet` | | Search one sheet. query: query=Press%207. |
| `Search` | `GET` | `/2.0/search?{value.json.query}` | `devops/smartsheet/search/all` | | Search everything the token can see. query: query=Press%207\&scopes=cellData\&modifiedSince=2026-10-01T00:00:00Z. |
| `SheetAttachmentsList` | `GET` | `/2.0/sheets/{value.json.sheet}/attachments?{value.json.query}` | `devops/smartsheet/attachments/list` | | Attachments on a sheet and its rows. query e.g. includeAll=true (or empty). |
| `AttachmentGet` | `GET` | `/2.0/sheets/{value.json.sheet}/attachments/{value.json.attachment}` | `devops/smartsheet/attachments/get` | | One attachment with a temporary download url. |
| `RowAttachmentsList` | `GET` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}/attachments?{value.json.query}` | `devops/smartsheet/rows/attachments/list` | | Attachments on one row. query e.g. includeAll=true (or empty). |
| `RowAttachmentAddUrl` | `POST` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}/attachments` | `devops/smartsheet/rows/attachments/add-url` | Yes | Attach a link to a row (no file upload). body: \{"attachmentType":"LINK","url":"[https://broker.example.com/panels/press7","name":"Press](https://broker.example.com/panels/press7","name":"Press) 7 trend"}. |
| `DiscussionsList` | `GET` | `/2.0/sheets/{value.json.sheet}/discussions?{value.json.query}` | `devops/smartsheet/discussions/list` | | Discussions on a sheet. query e.g. include=comments\&includeAll=true. |
| `RowDiscussionsList` | `GET` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}/discussions?{value.json.query}` | `devops/smartsheet/rows/discussions/list` | | Discussions on one row. query e.g. include=comments (or empty). |
| `RowDiscussionCreate` | `POST` | `/2.0/sheets/{value.json.sheet}/rows/{value.json.row}/discussions` | `devops/smartsheet/rows/discussions/create` | Yes | Start a comment thread on a row. body: \{"comment":\{"text":"Temperature back to 71 C at 14:20"}}. |
| `DiscussionCommentAdd` | `POST` | `/2.0/sheets/{value.json.sheet}/discussions/{value.json.discussion}/comments` | `devops/smartsheet/discussions/comments/add` | Yes | Reply in an existing discussion. body: \{"text":"Bearing replaced, line restarted"}. |
| `UpdateRequestCreate` | `POST` | `/2.0/sheets/{value.json.sheet}/updaterequests` | `devops/smartsheet/update-requests/create` | Yes | Ask someone to fill in rows by email (e.g. shift lead signs off a downtime row). body: \{"sendTo":\[\{"email":"[shift.lead@example.com](mailto:shift.lead@example.com)"}],"rowIds":\[\<rowId>],"columnIds":\[\<id>,\<id>],"subject":"Confirm downtime cause","message":"Press 7 stopped 42 min","ccMe":false,"includeAttachments":false,"includeDiscussions":false}. |
| `ReportsList` | `GET` | `/2.0/reports?{value.json.query}` | `devops/smartsheet/reports/list` | | Reports the token can see. query e.g. modifiedSince=2026-10-01T00:00:00Z (or empty). |
| `ReportGet` | `GET` | `/2.0/reports/{value.json.report}?{value.json.query}` | `devops/smartsheet/reports/get` | | One report with rows across its source sheets (e.g. all open downtime rows plant-wide). query e.g. pageSize=100\&page=1\&include=sourceSheets. |
| `WorkspacesList` | `GET` | `/2.0/workspaces?{value.json.query}` | `devops/smartsheet/workspaces/list` | | Workspaces (token-based pagination). query e.g. maxItems=100 (then lastKey=\<lastKey>). |
| `WorkspaceChildrenList` | `GET` | `/2.0/workspaces/{value.json.workspace}/children?{value.json.query}` | `devops/smartsheet/workspaces/children/list` | | Sheets, reports, dashboards and folders in a workspace. query e.g. childrenResourceTypes=sheets,folders\&maxItems=100. |
| `FolderChildrenList` | `GET` | `/2.0/folders/{value.json.folder}/children?{value.json.query}` | `devops/smartsheet/folders/children/list` | | Contents of a folder. query e.g. childrenResourceTypes=sheets\&maxItems=100. |
| `DashboardsList` | `GET` | `/2.0/sights?{value.json.query}` | `devops/smartsheet/dashboards/list` | | Dashboards (sights). query e.g. maxItems=100 (or empty). |
| `DashboardGet` | `GET` | `/2.0/sights/{value.json.dashboard}?{value.json.query}` | `devops/smartsheet/dashboards/get` | | One dashboard with its widgets. dashboard = sight id. query e.g. level=4 (or empty). |
| `WebhooksList` | `GET` | `/2.0/webhooks?{value.json.query}` | `devops/smartsheet/webhooks/list` | | Webhooks owned by the token's user. query e.g. includeAll=true or pageSize=100 (or empty). |
| `WebhookCreate` | `POST` | `/2.0/webhooks` | `devops/smartsheet/webhooks/create` | Yes | Subscribe to sheet changes; Smartsheet posts them to a Coreflux ENABLE\_SERVER REST\_API connector. body: \{"name":"Porto line 2 downtime","callbackUrl":"[https://broker.example.com/smartsheet/events","scope":"sheet","scopeObjectId":\&lt;sheetId>,"events":\["\*.\*"\],"version":1\\}](https://broker.example.com/smartsheet/events","scope":"sheet","scopeObjectId":\&lt;sheetId>,"events":\["*.*"],"version":1\\}). Created disabled; enable with WebhookUpdate. |
| `WebhookGet` | `GET` | `/2.0/webhooks/{value.json.webhook}` | `devops/smartsheet/webhooks/get` | | One webhook (enabled, status such as ENABLED or DISABLED\_VERIFICATION\_FAILED, stats). |
| `WebhookUpdate` | `PUT` | `/2.0/webhooks/{value.json.webhook}` | `devops/smartsheet/webhooks/update` | Yes | Enable (starts the verification challenge), pause or retarget a webhook. body: \{"enabled":true} or \{"enabled":false} or \{"callbackUrl":"https\://..."}. |

## Limits

Smartsheet allows 300 requests per minute per token for most operations. Cell history and file attachments count ten times, which leaves 30 requests per minute. Above that Smartsheet answers `429` with error code 4003. Batch rows into one `RowsAdd` or `RowsUpdate` call instead of one call per value. Lists are paginated: use `page` and `pageSize` (or `includeAll=true`) on most lists, and `maxItems` and `lastKey` on workspaces, folder children and dashboards.

## Not packaged

* All DELETE endpoints (sheets, rows, columns, discussions, comments, attachments, webhooks) on purpose. Archive closed rows with `RowsMove` instead.
* File uploads (multipart or binary) to sheets, rows and comments. `RowAttachmentAddUrl` attaches links only.
* Sharing, groups, user administration, favorites, proofs, automation rules, cross-sheet references, publish settings, sheet import, event reporting (enterprise audit) and OAuth token exchange.
* The incoming webhook direction: Smartsheet posts callbacks to a separate `ENABLE_SERVER` REST\_API connector, which must answer the verification challenge.

## Suggested branches

`feat/rest-api-route-smartsheet` for the broker template and `feat/docs-rest-api-smartsheet` for this page.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.