Legacy Spreadsheets API Migration Guide

Table Of Contents

Legacy Spreadsheets API Migration Guide#

This guide helps developers transition from the legacy Spreadsheets API to the 2026-01-01 Spreadsheets API. The new API provides improved functionality and simplified endpoint paths.

High-Level Changes#

  • Endpoint Paths: All endpoints have been updated to new paths

  • Revision: The revision field used to be an integer. It is now an opaque string. This string can be used with the $revision query parameter when getting a Spreadsheet or Sheet to retrieve a specific version.

  • Scopes: OAuth scopes have been revised to match patterns going forward


Migration: Creating a Spreadsheet#

2022-01-01 Endpoint#

POST /spreadsheets/v1/spreadsheets

2026-01-01 Endpoint#

POST /files

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets to /files

  • File Kind: When creating a spreadsheet, you must specify "kind": "Spreadsheet" in the request body

  • Response Structure: The response now returns a unified File object instead of a SpreadsheetBody object

Request Example#

2022-01-01 Request#

POST /spreadsheets/v1/spreadsheets
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Quarterly Report"
}

2026-01-01 Request#

POST /files
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Quarterly Report",
  "kind": "Spreadsheet"
}

Response Example#

2022-01-01 Response#

{
  "data": {
    "name": "Quarterly Report"
  },
  "revision": 1
}

2026-01-01 Response#

{
  "id": "124efa2a142f472ba1ceab34ed18915f",
  "name": "Quarterly Report",
  "kind": "Spreadsheet",
  "container": "",
  "created": {
    "dateTime": "2019-10-28T15:03:27Z"
  },
  "modified": {
    "dateTime": "2019-10-28T15:03:27Z"
  },
  "type": "Spreadsheet",
  "template": false
}

HTTP Status#

  • 2022-01-01: 201 Created

  • 2026-01-01: 201 Created

Required Scopes#

  • 2022-01-01: data_tables|w

  • 2026-01-01: file:write


Migration: Deleting a Spreadsheet#

2022-01-01 Endpoint#

DELETE /spreadsheets/v1/spreadsheets/{spreadsheetId}

2026-01-01 Endpoint#

POST /files/{fileId}/trash

Key Changes#

  • HTTP Method: Changed from DELETE to POST

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId} to /files/{fileId}/trash

  • Request Body: The new endpoint requires a request body with trash options

Request Example#

2022-01-01 Request#

DELETE /spreadsheets/v1/spreadsheets/abc123def456
Authorization: Bearer {token}

2026-01-01 Request#

POST /files/76515a4224224565ba1fae5e69ceaafd/trash
Content-Type: application/json
Authorization: Bearer {token}

{}

Response Example#

2022-01-01 Response#

{
    "message":"Delete successful",
    "request_id":"68a4f1e5-5936-407f-8f3b-086df4338d92"
}

2026-01-01 Response#

HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://api.app.wdesk.com/operations/9b7dd722-cb79-4330-83da-f6c9633fc875

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 202 Accepted (asynchronous operation)

Required Scopes#

  • 2022-01-01: data_tables|w

  • 2026-01-01: file:write

Important Notes#

  • The new endpoint is asynchronous. Check the operation ID in the response to track the deletion status.

  • Files moved to trash can be recovered from the trash within a grace period.


Migration: Getting a Spreadsheet by ID#

2022-01-01 Endpoint#

GET /spreadsheets/v1/spreadsheets/{spreadsheetId}

2026-01-01 Endpoint#

GET /spreadsheets/{spreadsheetId}

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId} to /spreadsheets/{spreadsheetId}

  • Response Structure: The response now returns a unified Spreadsheet object instead of a wrapped response with data and revision properties

  • Query Parameters: The revision parameter is no longer available

Request Example#

2022-01-01 Request#

GET /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd
Authorization: Bearer {token}

2026-01-01 Request#

GET /spreadsheets/76515a4224224565ba1fae5e69ceaafd
Authorization: Bearer {token}

Response Example#

2022-01-01 Response#

{
  "data": {
    "created": "2026-01-07T22:00:58.67Z",
    "id": "76515a4224224565ba1fae5e69ceaafd",
    "last_modified": "2026-01-07T22:00:58.732362Z",
    "locked": false,
    "name": "Quarterly Report",
  },
  "request_id": "dddd9f93-d63d-45ce-9210-25622fbb0d47",
  "revision": 1707951
}

2026-01-01 Response#

{
  "id": "124efa2a142f472ba1ceab34ed18915f",
  "name": "Year-end review",
  "created": {
    "dateTime": "2018-10-21T15:03:27Z"
  },
  "modified": {
    "dateTime": "2018-10-21T15:03:27Z"
  },
  "template": false
}

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 200 OK

Required Scopes#

  • 2022-01-01: data_tables|r (read access to data tables)

  • 2026-01-01: file:read (read access to files)

Migration Tips#

  1. Update response parsing: Change from extracting data.property to directly accessing property on the response object.


Migration: Updating a Spreadsheet#

2022-01-01 Endpoint#

PUT /spreadsheets/v1/spreadsheets/{spreadsheetId}

2026-01-01 Endpoint#

PATCH /files/{fileId}

Key Changes#

  • HTTP Method: Changed from PUT to PATCH for partial updates

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId} to /files/{fileId}

  • Request Body Format: Changed from direct property object to JSON Patch (RFC 6902) format

  • Response Structure: The response now returns a unified File object instead of an EmptyResponse

Request Example#

2022-01-01 Request#

PUT /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd
Content-Type: application/json
Authorization: Bearer {token}
{
  "name": "Updated Spreadsheet Name"
}

2026-01-01 Request#

PATCH /files/76515a4224224565ba1fae5e69ceaafd
Content-Type: application/json
Authorization: Bearer {token}
[
  {
    "op": "replace",
    "path": "/name",
    "value": "Updated Spreadsheet Name"
  }
]

Response Example#

2022-01-01 Response#

{
  "message": "No content returned."
}

2026-01-01 Response#

{
  "id": "124efa2a142f472ba1ceab34ed18915f",
  "name": "Updated Spreadsheet Name",
  "kind": "Spreadsheet",
  "container": "",
  "created": {
    "dateTime": "2019-10-28T15:03:27Z"
  },
  "modified": {
    "dateTime": "2026-01-07T15:30:45Z"
  },
  "type": "Spreadsheet",
  "template": false
}

Supported PATCH Operations#

The 2026-01-01 endpoint supports the following JSON Patch operations:

  • /name: Update the file name using the replace operation

  • /container: Update the container (folder) using the replace operation

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 200 OK

Required Scopes#

  • 2022-01-01: data_tables|w

  • 2026-01-01: file:write

Important Notes#

  • The 2026-01-01 endpoint only supports one operation per request

  • Updates are applied asynchronously and may not be immediately reflected in subsequent requests

  • The response includes the updated File object with current timestamps

Migration Tips#

  1. Switch to JSON Patch format: Convert direct property updates to JSON Patch operations

  2. Handle multiple updates: If you need to update multiple properties, make separate PATCH requests for each

  3. Process response: Update your code to handle the File object response instead of an empty response



Migration: Retrieving Sheets in a Spreadsheet#

2022-01-01 Endpoint#

GET /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets

2026-01-01 Endpoint#

GET /spreadsheets/{spreadsheetId}/sheets

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets to /spreadsheets/{spreadsheetId}/sheets

  • Response Structure: Changed from wrapped response with data and revision properties to a SheetsListResult object

  • Sheet Object Structure: The new endpoint returns sheets with simplified structure including id, name, parent, index, children, and dataset properties

  • Pagination: The new endpoint supports pagination via @nextLink for large result sets

  • Revision: Use the $revision query parameter to retrieve sheets at a specific revision

Request Example#

2022-01-01 Request#

GET /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets
Authorization: Bearer {token}

2026-01-01 Request#

GET /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets
Authorization: Bearer {token}

Response Example#

2022-01-01 Response#

{
  "data": [
    {
      "id": "k78a604b74564afa76b5ba96755123456",
      "name": "Q1 Results",
      "parent_id": "",
      "index": 0,
      "child_ids": [],
      "locked": false,
      "input_mode": false,
      "restricted": false
    },
    {
      "id": "d10a604b74564afa86b5ba96755845652",
      "name": "Q2 Results",
      "parent_id": "",
      "index": 1,
      "child_ids": [],
      "locked": false,
      "input_mode": false,
      "restricted": false
    }
  ],
  "revision": 1707951
}

2026-01-01 Response#

{
  "data": [
    {
      "id": "242a56d3cc0742c8abad0820bd318b23",
      "name": "Q1",
      "parent": null,
      "index": 0,
      "children": [],
      "dataset": null,
      "customFields": {}
      "revision": "2c6438ab454f2d35",
      "table": {
        "revision": "2c6438ab454f2d35",
        "table": "WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJBW3"
      }
    },
    {
      "id": "132b55d1cd0543c1aaae0924bc328a24",
      "name": "Q2",
      "parent": null,
      "index": 1,
      "children": [],
      "dataset": null,
      "customFields": {},
      "revision": "2c6438ab454f2d35",
      "table": {
        "revision": "2c6438ab454f2d35",
        "table": "WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJCOg"
      }
    }
  ],
  "@nextLink": "<opaque_url>"
}

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 200 OK

Required Scopes#

  • 2022-01-01: data_tables|r (read access to data tables)

  • 2026-01-01: file:read (read access to files)

Migration Tips#

  1. Handle pagination: Implement pagination support by checking for the @nextLink property in the response and following the link for additional results

  2. Use new sheet properties: Update your code to work with the new sheet object structure that includes parent, index, children, and dataset properties

  3. Locks: Note that properties like locked and input_mode are reflected by the lock property on the sheet. This field can be set to lock if the sheet is locked or inputMode if the sheet is in input mode.


Migration: Creating a Sheet in a Spreadsheet#

2022-01-01 Endpoint#

POST /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets

2026-01-01 Endpoint#

POST /spreadsheets/{spreadsheetId}/sheets

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets to /spreadsheets/{spreadsheetId}/sheets

  • Request Body: Simplified request structure with optional properties

  • Required Fields: In the 2022-01-01 API, name, parent_id, and index were all required. In the 2026-01-01 API, only name is required; parent and index are optional

  • Response Structure: Changed from wrapped response with data, revision, and request_id properties to a direct Sheet object

  • Sheet Object Structure: The new endpoint returns sheets with simplified structure using parent (object) instead of parent_id (string), and children instead of child_ids

  • Default Behavior: If index is not specified, the sheet is created in the top-most position. If the name is not unique, a number is appended automatically

Request Example#

2022-01-01 Request#

POST /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Q3 Results",
  "parent_id": "",
  "index": 2
}

2026-01-01 Request#

POST /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Q3",
  "index": 2
}

Response Example#

2022-01-01 Response#

{
  "data": {
    "id": "k78a604b74564afa76b5ba96755123456",
    "name": "Q3 Results",
    "parent_id": "",
    "index": 2,
    "child_ids": [],
    "locked": false,
    "input_mode": false,
    "restricted": false
  },
  "revision": 1707952,
  "request_id": "a1b2c3d4-e5f6-4789-0123-456789abcdef"
}

2026-01-01 Response#

{
  "id": "281c26d8ca0145c2cabe1714dc318c26",
  "name": "Q3",
  "parent": null,
  "index": 2,
  "children": [],
  "dataset": null
}

HTTP Status#

  • 2022-01-01: 201 Created

  • 2026-01-01: 201 Created

Required Scopes#

  • 2022-01-01: data_tables|w (write access to data tables)

  • 2026-01-01: file:write (write access to files)

Migration Tips#

  1. Simplify request body: Remove the parent_id parameter if creating a top-level sheet (the default behavior)

  2. Use -1 for end positioning: To position a sheet at the end of its siblings without knowing the count, use index: -1 in both APIs

  3. Update response parsing: Change from extracting data.property to directly accessing property on the response object

  4. Handle automatic naming: The new API automatically appends numbers to duplicate sheet names, so you don’t need to implement your own uniqueness logic

  5. Parent object instead of ID: The response now includes a parent object (or null for top-level sheets) instead of a parent_id string


Migration: Deleting a Sheet from a Spreadsheet#

2022-01-01 Endpoint#

DELETE /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}

2026-01-01 Endpoint#

DELETE /spreadsheets/{spreadsheetId}/sheets/{sheetId}

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId} to /spreadsheets/{spreadsheetId}/sheets/{sheetId}

  • Response Structure: Changed from a response with message and request_id properties to no content (empty response body)

  • HTTP Status: Changed from 200 OK to 204 No Content

  • Recursive Deletion: Both APIs delete a sheet and all of its child sheets recursively

Request Example#

2022-01-01 Request#

DELETE /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456
Authorization: Bearer {token}

2026-01-01 Request#

DELETE /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/281c26d8ca0145c2cabe1714dc318c26
Authorization: Bearer {token}

Response Example#

2022-01-01 Response#

{
  "message": "No content returned.",
  "request_id": "a1b2c3d4-e5f6-4789-0123-456789abcdef"
}

2026-01-01 Response#

HTTP/1.1 204 No Content

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 204 No Content

Required Scopes#

  • 2022-01-01: data_tables|w (write access to data tables)

  • 2026-01-01: file:write (write access to files)

Important Notes#

  • Both endpoints permanently delete the specified sheet and all of its child sheets (recursively)

  • The 2026-01-01 endpoint returns an empty response body with a 204 No Content status, following REST best practices for successful DELETE operations

  • Once deleted, sheets cannot be recovered, so ensure you have proper confirmation workflows in your application

Migration Tips#

  1. Update status code handling: Change your success handler to expect 204 No Content instead of 200 OK

  2. Handle empty response: Update your code to handle an empty response body rather than parsing JSON content

  3. Remove request_id tracking: The new endpoint doesn’t return a request_id in the response; use the X-Request-ID header if you need to track requests for debugging

  4. Confirm before deletion: Implement proper confirmation dialogs in your application, as the deletion is permanent and includes all child sheets


Migration: Getting a Sheet by ID#

2022-01-01 Endpoint#

GET /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}

2026-01-01 Endpoint#

GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId} to /spreadsheets/{spreadsheetId}/sheets/{sheetId}

  • Response Structure: Changed from wrapped response with data, revision, and request_id properties to a direct Sheet object

  • Sheet Object Structure: The new endpoint returns sheets with simplified structure using parent (object/null) instead of parent_id (string), and children (array) instead of child_ids (array of strings)

  • Lock Properties: The locked, input_mode, and restricted properties from the 2022-01-01 API are no longer present. Lock status can be checked via the lock property.

  • Revision: Use the $revision query parameter to retrieve the sheet at a specific revision.

Request Example#

2022-01-01 Request#

GET /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456
Authorization: Bearer {token}

2026-01-01 Request#

GET /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/242a56d3cc0742c8abad0820bd318b23
Authorization: Bearer {token}

Response Example#

2022-01-01 Response#

{
  "data": {
    "id": "k78a604b74564afa76b5ba96755123456",
    "name": "Q1 Results",
    "parent_id": "",
    "index": 0,
    "child_ids": [
      "h65a604b74564afa86b5ba96755845652"
    ],
    "locked": false,
    "input_mode": false,
    "restricted": false
  },
  "revision": 1707951,
  "request_id": "a1b2c3d4-e5f6-4789-0123-456789abcdef"
}

2026-01-01 Response#

{
  "id": "242a56d3cc0742c8abad0820bd318b23",
  "name": "Q1",
  "parent": null,
  "index": 0,
  "children": [
    {
      "id": "132b55d1cd0543c1aaae0924bc328a24",
      "name": "Q1 Subtotals"
    }
  ],
  "dataset": null
}

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 200 OK

Required Scopes#

  • 2022-01-01: data_tables|r (read access to data tables)

  • 2026-01-01: file:read (read access to files)

Migration Tips#

  1. Update response parsing: Change from extracting data.property to directly accessing property on the response object

  2. Handle parent structure: Update code that checks parent_id to check for parent object (will be null for top-level sheets)

  3. Process children array: Instead of just IDs in child_ids, the new endpoint returns partial Sheet objects in the children array with both id and name properties

  4. Handle lock status: If you need to check lock status, note that locked, input_mode, and restricted properties are replaced by a lock property in the new API (check the Sheets List migration section for details)


Migration: Updating a Sheet in a Spreadsheet#

2022-01-01 Endpoint#

PUT /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}

2026-01-01 Endpoint#

PATCH /spreadsheets/{spreadsheetId}/sheets/{sheetId}

Key Changes#

  • HTTP Method: Changed from PUT to PATCH for partial updates

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId} to /spreadsheets/{spreadsheetId}/sheets/{sheetId}

  • Request Body Format: Changed from direct property object to JSON Patch (RFC 6902) format

  • Response Status: Changed from 200 OK to 202 Accepted (asynchronous operation)

  • Response Structure: The new endpoint is a long-running operation that returns a Location header for polling results

  • Additional Capabilities: The new endpoint supports updating the lock property to control sheet locking

Request Example#

2022-01-01 Request (Rename Only)#

PUT /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Q1 Final"
}

2022-01-01 Request (Move and Rename)#

PUT /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Q1 Final",
  "parent_id": "d10a604b74564afa86b5ba96755845652",
  "index": 0
}

2026-01-01 Request (Rename Only)#

PATCH /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/242a56d3cc0742c8abad0820bd318b23
Content-Type: application/json
Authorization: Bearer {token}

[
  {
    "op": "replace",
    "path": "/name",
    "value": "Q1 Final"
  }
]

2026-01-01 Request (Move and Rename)#

PATCH /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/242a56d3cc0742c8abad0820bd318b23
Content-Type: application/json
Authorization: Bearer {token}

[
  {
    "op": "replace",
    "path": "/name",
    "value": "Q1 Final"
  },
  {
    "op": "replace",
    "path": "/parent",
    "value": {
      "id": "132b55d1cd0543c1aaae0924bc328a24"
    }
  },
  {
    "op": "replace",
    "path": "/index",
    "value": 0
  }
]

2026-01-01 Request (Lock a Sheet)#

PATCH /spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/242a56d3cc0742c8abad0820bd318b23
Content-Type: application/json
Authorization: Bearer {token}

[
  {
    "op": "replace",
    "path": "/lock",
    "value": "lock"
  }
]

Response Example#

2022-01-01 Response#

{
  "message": "No content returned.",
  "request_id": "a1b2c3d4-e5f6-4789-0123-456789abcdef"
}

2026-01-01 Response#

HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://api.app.wdesk.com/operations/9b7dd722-cb79-4330-83da-f6c9633fc875

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 202 Accepted (asynchronous operation)

Required Scopes#

  • 2022-01-01: data_tables|w (write access to data tables)

  • 2026-01-01: file:write (write access to files)

Supported PATCH Operations#

The 2026-01-01 endpoint supports the following JSON Patch operations:

  • /name: Update the sheet name using the replace operation

  • /index: Update the sheet’s position among siblings using the replace operation

  • /parent: Update the sheet’s parent using the replace operation (requires an object with an id property)

  • /lock: Update the sheet’s lock status using the replace operation (values: "lock" for locked, "inputMode" for input mode, or null for unlocked)

Important Notes#

  • In the 2022-01-01 API, if name is set to null or not included, the sheet will not be renamed. If both parent_id and index are set to null or not included, the sheet will not be moved.

  • The 2026-01-01 endpoint is asynchronous. Check the Location header in the response to poll for operation completion.

  • When moving a sheet to a new parent, you can optionally specify an index to control its position among the new siblings.

  • Use index: -1 to position a sheet at the end of its siblings without knowing the total count.

  • The new endpoint allows multiple properties to be updated in a single request using multiple JSON Patch operations.

Migration Tips#

  1. Switch to JSON Patch format: Convert direct property updates to JSON Patch operations with op, path, and value fields

  2. Handle parent object: When updating the parent, use an object with an id property instead of a simple string ID

  3. Implement operation polling: Since the operation is asynchronous, implement polling logic using the Location header to track completion

  4. Batch multiple updates: Take advantage of the ability to update multiple properties in a single request by including multiple JSON Patch operations

  5. Handle lock operations: Use the new /lock path to programmatically lock or unlock sheets


Migration: Getting Table Cell Content with Rich Formatting#

2022-01-01 Endpoint#

GET /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}/data/{region}

2026-01-01 Endpoint#

GET /content/tables/{tableId}/cells

Key Changes#

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}/data/{region} to /content/tables/{tableId}/cells

  • Identifiers: Changed from using spreadsheetId and sheetId to using tableId (the sheet’s underlying table identifier)

  • Range Specification: Changed from A1-style notation (region path parameter) to numeric row/column query parameters (startRow, stopRow, startColumn, stopColumn)

  • Response Content: The new endpoint returns rich formatting information including cell properties, borders, colors, alignment, and rich text content, while the old endpoint only returned cell values

  • Response Structure: Changed from RangeDataResponse to TableCellsResult with detailed cell properties and formatting

  • Pagination: Changed from page/per_page/next_url to $next/$maxcellsperpage/@nextLink

  • Value Format: The new endpoint returns both value (with rich formatting) and rawValue (plain text) for each cell

  • Revision Access: Both endpoints support the $revision query parameter to retrieve cells at a specific revision

Request Example#

2022-01-01 Request (A1:C5 range)#

GET /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456/data/A1%3AC5
Authorization: Bearer {token}

2022-01-01 Request (With pagination)#

GET /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456/data/A1%3AC5?per_page=1000
Authorization: Bearer {token}

2026-01-01 Request (Rows 0-4, Columns 0-2)#

GET /content/tables/WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJBW3/cells?startRow=0&stopRow=4&startColumn=0&stopColumn=2
Authorization: Bearer {token}

2026-01-01 Request (With pagination)#

GET /content/tables/WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJBW3/cells?startRow=0&stopRow=4&startColumn=0&stopColumn=2&$maxcellsperpage=1000
Authorization: Bearer {token}

Response Example#

2022-01-01 Response#

{
  "data": {
    "range": "A1:C3",
    "values": [
      ["First", "Second", "Third"],
      ["1", "2", ""],
      ["3", "4", "5"]
    ]
  },
  "revision": 1707951,
  "request_id": "d6a6ce3f-f120-4104-9587-a5a2dc45626c"
}

2026-01-01 Response#

{
  "data": [
    {
      "cells": [
        {
          "properties": {
            "borders": {
              "bottom": {
                "color": {
                  "red": 128,
                  "green": 128,
                  "blue": 128
                },
                "style": "single",
                "weight": 1
              },
              "left": {
                "color": {
                  "red": 128,
                  "green": 128,
                  "blue": 128
                },
                "style": "single",
                "weight": 1
              },
              "right": {
                "color": {
                  "red": 128,
                  "green": 128,
                  "blue": 128
                },
                "style": "single",
                "weight": 1
              },
              "top": {
                "color": {
                  "red": 128,
                  "green": 128,
                  "blue": 128
                },
                "style": "single",
                "weight": 1
              }
            },
            "fillColor": {
              "red": 136,
              "green": 204,
              "blue": 255
            },
            "horizontalAlignment": "left",
            "indent": 10,
            "verticalAlignment": "middle"
          },
          "rawValue": "Hello World",
          "value": {
            "richText": {
              "paragraphs": [
                {
                  "elements": [
                    {
                      "textSpan": {
                        "format": {},
                        "length": 5,
                        "offset": 0,
                        "text": "Hello",
                        "type": "text"
                      },
                      "type": "textSpan"
                    }
                  ],
                  "format": {
                    "bold": true,
                    "font": "Arial",
                    "size": 24
                  },
                  "index": 3
                }
              ]
            },
            "type": "richText"
          }
        }
      ]
    }
  ],
  "range": {
    "startColumn": 0,
    "startRow": 0,
    "stopColumn": 0,
    "stopRow": 0
  },
  "revision": "24601abc"
}

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 200 OK

Required Scopes#

  • 2022-01-01: data_tables|r (read access to data tables)

  • 2026-01-01: file:read (read access to files)

Important Notes#

  • The new endpoint requires the tableId, which can be obtained from the Sheet object’s table.table property when retrieving sheets

  • The 2022-01-01 endpoint uses A1-style notation (e.g., A1:C5) while the 2026-01-01 endpoint uses zero-based numeric indices for rows and columns

  • The new endpoint returns comprehensive formatting information including borders, colors, alignment, indentation, and rich text formatting

  • Both value (with formatting) and rawValue (plain text) are provided for each cell in the new endpoint

  • Range parameters in the 2026-01-01 endpoint are all optional. Omitting a parameter makes the range unbounded in that direction

  • Pagination uses @nextLink in the 2026-01-01 endpoint for retrieving subsequent pages

  • The $maxcellsperpage default and maximum is 50,000 cells in both APIs

Migration Tips#

  1. Obtain the tableId: Before calling the new endpoint, retrieve the sheet and extract the table.table property to get the tableId

  2. Convert A1 notation to numeric indices: Convert A1-style ranges (e.g., A1:C5) to zero-based row/column indices:

    • Column A = 0, B = 1, C = 2, etc.

    • Row 1 = 0, Row 2 = 1, Row 3 = 2, etc.

    • Example: A1:C5 becomes startRow=0&stopRow=4&startColumn=0&stopColumn=2

  3. Parse rich formatting: Update your code to handle the new response structure with cell properties and rich text formatting

  4. Use rawValue for simple text: If you only need plain text values (like in the old API), use the rawValue property

  5. Handle pagination: Use @nextLink for pagination instead of constructing URLs with page numbers

  6. Update response parsing: The data property is now an array of objects containing cells arrays, rather than a simple 2D array of values

  7. Handle revision as string: The revision is now an opaque string instead of an integer


Migration: Editing Table Cells with Rich Formatting#

2022-01-01 Endpoint#

PUT /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}/data/{region}

2026-01-01 Endpoint#

POST /content/tables/{tableId}/cells/edit

Key Changes#

  • HTTP Method: Changed from PUT to POST

  • Path: Changed from /spreadsheets/v1/spreadsheets/{spreadsheetId}/sheets/{sheetId}/data/{region} to /content/tables/{tableId}/cells/edit

  • Identifiers: Changed from using spreadsheetId and sheetId to using tableId (the sheet’s underlying table identifier)

  • Range Specification: Changed from A1-style notation (region path parameter) to numeric row/column properties in the request body (startRow, stopRow, startColumn, stopColumn)

  • Request Body Structure: Changed from simple 2D array of values to batch edit format supporting multiple edit operations with rich formatting capabilities

  • Edit Capabilities: The new endpoint supports comprehensive cell editing including text, formatting, styles, borders, properties, and locking

  • Response Status: Changed from 200 OK to 202 Accepted (asynchronous operation)

  • Response Structure: Changed from EmptyResponse with message to a long-running operation with Location header for polling

  • Locked Cell Handling: The new endpoint includes a lockedCellEditMode property to control how edits are handled for locked cells

  • Revision Support: Both endpoints support revision-based editing, but the 2026-01-01 API uses an opaque string revision instead of integer

Request Example#

2022-01-01 Request (Simple Text Update)#

PUT /spreadsheets/v1/spreadsheets/76515a4224224565ba1fae5e69ceaafd/sheets/k78a604b74564afa76b5ba96755123456/data/A1%3AC3
Content-Type: application/json
Authorization: Bearer {token}

{
  "values": [
    ["First", "Second", "Third"],
    ["1", "2", ""],
    ["3", "4", "5"]
  ]
}

2026-01-01 Request (Simple Text Update)#

POST /content/tables/WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJBW3/cells/edit
Content-Type: application/json
Authorization: Bearer {token}

{
  "data": [
    {
      "type": "setCellsText",
      "setCellsText": {
        "range": {
          "startRow": 0,
          "stopRow": 2,
          "startColumn": 0,
          "stopColumn": 2
        },
        "text": [
          ["First", "Second", "Third"],
          ["1", "2", ""],
          ["3", "4", "5"]
        ]
      }
    }
  ]
}

2026-01-01 Request (Multiple Edit Operations)#

POST /content/tables/WAwoICAsJfFtQSC4oT29AwFaRUY8Sg99wgBW3nodhoGQmSqagANsKJBW3/cells/edit
Content-Type: application/json
Authorization: Bearer {token}

{
  "data": [
    {
      "type": "setCellsText",
      "setCellsText": {
        "range": {
          "startRow": 0,
          "stopRow": 2,
          "startColumn": 0,
          "stopColumn": 2
        },
        "text": [
          ["First", "Second", "Third"],
          ["1", "2", ""],
          ["3", "4", "5"]
        ]
      }
    },
    {
      "type": "formatCells",
      "formatCells": {
        "ranges": [
          {
            "startRow": 0,
            "stopRow": 0,
            "startColumn": 0,
            "stopColumn": 2
          }
        ],
        "bold": true,
        "size": 14
      }
    }
  ],
  "lockedCellEditMode": "strict"
}

Response Example#

2022-01-01 Response#

{
  "message": "No content returned.",
  "request_id": "a1b2c3d4-e5f6-4789-0123-456789abcdef"
}

2026-01-01 Response#

HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://api.app.wdesk.com/operations/9b7dd722-cb79-4330-83da-f6c9633fc875
Retry-After: 5

HTTP Status#

  • 2022-01-01: 200 OK

  • 2026-01-01: 202 Accepted (asynchronous operation)

Required Scopes#

  • 2022-01-01: data_tables|w (write access to data tables)

  • 2026-01-01: file:write (write access to files)

Supported Edit Types#

The 2026-01-01 endpoint supports the following edit types (up to 100 edits per request):

  • setCellsText: Write plain text to cells, preserving cell properties and some formatting

  • richCellBatchEdit: Write rich text with formatting to cells

  • clearCellsText: Clear text content from cells

  • formatCells: Apply text formatting (bold, italic, underline, font, size, color, etc.)

  • clearCellsFormat: Clear text formatting from cells

  • setCellsStyle: Apply cell styles (number format, alignment, etc.)

  • setCellsProperties: Set cell properties (background color, horizontal/vertical alignment, indent, etc.)

  • clearCellsProperties: Clear cell properties

  • setCellsBorders: Apply borders to cells

  • clearCellsBorders: Clear borders from cells

  • setCellsLock: Lock or unlock cells

  • setInputCells: Configure cells for input mode

Important Notes#

  • The new endpoint requires the tableId, which can be obtained from the Sheet object’s table.table property when retrieving sheets

  • The 2022-01-01 endpoint uses A1-style notation (e.g., A1:C3) while the 2026-01-01 endpoint uses zero-based numeric indices for rows and columns in the request body

  • The new endpoint is asynchronous. Use the Location header to poll for operation completion

  • In the 2026-01-01 API, you can batch multiple edit operations (up to 100) in a single request for better performance

  • The lockedCellEditMode property controls behavior for locked cells: strict (default) will fail if any locked cells are in the edit range, while trim will skip locked cells

  • The provided text/edits may not be larger than the specified range. Any null or missing elements will not modify the corresponding cell

  • Both endpoints support revision-based editing to target a specific table version

Migration Tips#

  1. Obtain the tableId: Before calling the new endpoint, retrieve the sheet and extract the table.table property to get the tableId

  2. Convert A1 notation to numeric indices: Convert A1-style ranges (e.g., A1:C3) to zero-based row/column indices:

    • Column A = 0, B = 1, C = 2, etc.

    • Row 1 = 0, Row 2 = 1, Row 3 = 2, etc.

    • Example: A1:C3 becomes startRow: 0, stopRow: 2, startColumn: 0, stopColumn: 2

  3. Wrap simple text updates: Wrap your 2D array of values in the setCellsText edit format with the data array and appropriate type field

  4. Leverage batch edits: Take advantage of the ability to combine multiple operations (text updates, formatting, styling) in a single request

  5. Handle asynchronous operation: Implement polling logic using the Location header in the response to track operation completion

  6. Use Retry-After header: Respect the Retry-After header value (in seconds) when polling for results or retrying after rate limits

  7. Update status code handling: Change success handler to expect 202 Accepted instead of 200 OK

  8. Handle locked cells: Set lockedCellEditMode to trim if you want to skip locked cells instead of failing the entire operation

  9. Handle revision as string: The revision is now an opaque string instead of an integer

  10. Consider edit capabilities: The new endpoint provides extensive formatting and styling capabilities beyond simple text updates