Spreadsheet Sheet Data Guide#
The Workiva Spreadsheets API lets you read cell data and formatting from sheets, write values, apply formatting across multiple ranges in a single request, and manage rows, columns, merges, and borders programmatically.
Table of Contents#
Prerequisites & Authentication#
All requests to the Workiva API require:
A valid OAuth 2.0 Bearer token
The
X-Version: 2026-01-01header on every requestThe appropriate OAuth scopes for each operation (noted per endpoint below)
export TOKEN="your_access_token_here"
export SPREADSHEET_ID="your-spreadsheet-id"
export SHEET_ID="your-sheet-id"
Important: Always include
X-Version: 2026-01-01on all requests. Omitting this header causes the API to default to the 2022-01-01 version, which uses different path prefixes and may return unexpected results.
Key Concepts#
Concept |
Description |
|---|---|
SheetUpdate |
The request body for the update sheet content endpoint. Each request can set only one top-level update field (e.g., |
SheetData |
The response from the retrieve data from a sheet endpoint. Contains cell values, formatting (both directly applied and effective/inherited), column and row metadata, and merged ranges. |
Range |
A 0-indexed object with |
A1 Notation |
A string like |
Async Operations |
All update operations return |
Note: The
Rangeobject (0-indexed, used in update request bodies) and A1 notation (1-indexed, used in query parameters and the values endpoint path) are two different ways to address cells. They are not interchangeable.
Understanding “One Update Field Per Request”#
The update sheet content endpoint documentation states:
“Each SheetUpdate can have only one update field set per request.”
This sentence is easy to misread. Here is what it actually means, and what it does not mean.
What it means: Each request body can include only one top-level field from the SheetUpdate object. You pick one of applyFormats, editCells, editRange, applyBorders, insertRows, deleteColumns, etc. You cannot combine applyFormats and editCells in the same request.
What it does NOT mean: It does not mean you can only apply one format, edit one cell, or target one range per request. The value inside each top-level field is typically an array. You can pack as many operations as you need into that array, all executed in a single API call.
The wrong approach vs. the right approach#
Suppose you need to format a 50-row financial report: bold the header, apply currency formatting to 10 data columns, shade alternating rows, and add a border under the totals row.
Wrong approach (what causes rate-limit escalations):
Send one request per format, per range. This turns a simple formatting job into dozens of API calls:
Request 1: applyFormats → bold header row
Request 2: applyFormats → currency format column B
Request 3: applyFormats → currency format column C
Request 4: applyFormats → currency format column D
...
Request 12: applyFormats → shade row 2 background
Request 13: applyFormats → shade row 4 background
...
Request 40: applyBorders → border under totals
At 60 requests per minute (the update endpoint’s workspace-wide rate limit), this workflow stalls almost immediately.
Right approach (one request per update type):
Batch everything into the formats array. All 50 rows of formatting go in a single call:
Request 1: applyFormats → formats: [ bold header, currency col B-K, shading rows 2/4/6/... ]
Request 2: applyBorders → borders: [ bottom border on totals row ]
Two requests instead of 40+. The formats array and borders array each accept multiple objects, and each object can target multiple ranges.
Important: The update endpoint is rate-limited to as low as 60 requests per minute, shared across your entire workspace. Every unnecessary request counts against that limit for all users and integrations in the workspace. Always batch operations into arrays rather than sending one-operation-per-request.
Quick reference: what can be batched within a single request#
Top-level field |
Array field inside it |
What you can batch |
|---|---|---|
|
|
Multiple format combinations, each targeting different ranges |
|
|
Multiple border styles, each targeting different ranges |
|
|
Many individual cell value updates across the sheet |
|
|
Multiple ranges to clear in one pass |
|
|
Multiple ranges to clear in one pass |
|
|
Multiple row insertions at different positions |
|
|
Multiple column insertions at different positions |
|
|
Multiple row intervals to delete |
|
|
Multiple column intervals to delete |
|
|
Multiple ranges to merge |
Retrieving Sheet Data#
Use retrieve data from a sheet to get cell values, formatting, column/row metadata, and merged ranges. This is the richest read endpoint, returning everything about each cell including its raw value, calculated value, directly applied formats, and effective (inherited) formats.
Required scope: file:read
Basic Retrieval#
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/sheetdata
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/sheetdata" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01"
Response (200 OK):
{
"@nextLink": "<opaque_url>",
"data": {
"cells": [
[
{
"calculatedValue": 2,
"effectiveFormats": {
"cellFormat": {
"backgroundColor": "#d0e8ff",
"horizontalAlign": "RIGHT",
"verticalAlign": "BOTTOM"
},
"textFormat": {
"bold": true,
"fontColor": "#000000",
"fontFamily": "Arial",
"fontSize": 10
},
"valueFormat": {
"valueFormatType": "CURRENCY",
"precision": { "auto": false, "value": 2 },
"showCurrencySymbol": true,
"showThousandsSeparator": true
}
},
"formats": {
"cellFormat": { "backgroundColor": "#d0e8ff" },
"textFormat": { "bold": true },
"valueFormat": { "valueFormatType": "CURRENCY" }
},
"value": "=1+1"
}
]
],
"columnMetadata": [
{ "hidden": false, "size": 75 }
],
"rowMetadata": [
{ "filtered": false, "hidden": false, "size": 16 }
],
"merges": [],
"range": {
"startColumn": 0,
"startRow": 0,
"stopColumn": 0,
"stopRow": 0
}
}
}
Tip: The
cellsarray is row-major order. Each element in the outer array is a row; each element in the inner array is a cell. Theformatsobject shows formats directly applied to the cell, whileeffectiveFormatsincludes inherited formats (from row, column, or sheet defaults).
Important: This endpoint is rate-limited to as low as 600 requests per minute, shared across your workspace. When you receive a
429 Too Many Requestsresponse, check theRetry-Afterheader and wait that many seconds before retrying.
Retrieving a Specific Cell Range#
Use the $cellrange query parameter with A1 notation to limit the response to a specific area.
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/sheetdata?$cellrange=A1:D10
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/sheetdata" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01" \
--data-urlencode '$cellrange=A1:D10'
Tip: Omitting
$cellrangereturns the entire sheet. For large sheets, always specify a range to avoid hitting the 50,000-cell pagination limit.
Filtering Response Fields#
Use the $fields parameter to return only the cell properties you need. Field paths are rooted at the data object.
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/sheetdata?$fields=cells.calculatedValue,cells.formats.valueFormat
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/sheetdata" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01" \
--data-urlencode '$cellrange=A1:C5' \
--data-urlencode '$fields=cells.calculatedValue,cells.formats.valueFormat'
Tip: Use
$fieldsto reduce response size when you only need values or only need formatting. For example,$fields=cells.value,cells.calculatedValuereturns just the raw and calculated values without any formatting data.
Pagination#
The default and maximum page size is 50,000 cells. If the requested range contains more cells, the response includes an @nextLink URL. Follow it to get the next page.
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/sheetdata?$maxcellsperpage=10000
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/sheetdata" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01" \
--data-urlencode '$cellrange=A1:Z1000' \
--data-urlencode '$maxcellsperpage=10000'
When @nextLink is present in the response, fetch that URL directly (it includes all necessary parameters) to retrieve the next page of results.
Retrieving Range Values#
Use retrieve a list of range values when you need just the cell values without formatting or metadata. This endpoint is lighter-weight than sheetdata and uses A1 notation in the URL path.
Required scope: file:read
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/values/{range}
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/values/A1:C3" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01"
Response (200 OK):
{
"data": [
{
"range": "A1:C3",
"values": [
["First", "Second", "Third"],
[1, 2, ""],
[3, 4, 5]
]
}
]
}
Raw vs. Calculated Values#
Use $valuestyle to control whether formulas return their formula string or their computed result.
GET /spreadsheets/{spreadsheetId}/sheets/{sheetId}/values/A1:B2?$valuestyle=calculated
curl -X GET "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/values/A1:B2" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01" \
--data-urlencode '$valuestyle=calculated'
|
Formula cell |
Non-formula cell |
|---|---|---|
|
|
|
|
|
|
When to Use Each Read Endpoint#
Need |
Use |
Why |
|---|---|---|
Cell values only, no formatting |
|
Lighter response, simpler structure |
Cell values with formatting |
|
Returns |
Column widths, row heights, hidden state |
|
Returns |
Merged ranges |
|
Returns |
Formula strings and calculated results |
Either |
|
Important: Both endpoints always return values in Ones scale, regardless of the cell’s
enteredInorshownInformatting. If a cell displays “1.5” in Thousands scale, the API returns1500.
Writing Cell Values#
There are three ways to write values to cells. Each has different strengths.
Approach |
Best For |
Addressing |
Async? |
|---|---|---|---|
|
Scattered, non-contiguous cells |
0-indexed row/column |
Yes |
|
Contiguous rectangular block (0-indexed) |
0-indexed Range object |
Yes |
|
Contiguous rectangular block (A1 notation) |
A1 notation in URL path |
Yes |
Writing Individual Cells with editCells#
Use editCells when you need to update specific cells that aren’t in a contiguous block.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"editCells": {
"cells": [
{ "column": 0, "row": 0, "value": "Revenue" },
{ "column": 1, "row": 0, "value": "Q1" },
{ "column": 2, "row": 0, "value": "Q2" },
{ "column": 0, "row": 5, "value": "Total" },
{ "column": 1, "row": 5, "value": 15000 },
{ "column": 2, "row": 5, "value": 22000 }
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Response (202 Accepted):
{
"operationLocation": "https://api.app.wdesk.com/operations/128f274395254cf17eda6b3eb3d021b9"
}
Tip: The
cellsarray can contain multiple cells in a single request. Batch your edits into one call rather than making separate requests per cell.
Both editCells and editRange support an optional options object:
Option |
Type |
Description |
|---|---|---|
|
boolean |
When |
|
boolean |
When |
Example with options:
{
"editCells": {
"cells": [
{ "column": 1, "row": 1, "value": 1.5 }
],
"options": {
"applyEnteredInScaling": true,
"skipEditMergeChildren": true
}
}
}
Writing a Contiguous Range with editRange#
Use editRange when updating a rectangular block of cells using 0-indexed coordinates.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"editRange": {
"range": {
"startColumn": 0,
"startRow": 0,
"stopColumn": 2,
"stopRow": 1
},
"values": [
["Revenue", "Q1", "Q2"],
["Product A", 15000, 22000]
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Response (202 Accepted):
{
"operationLocation": "https://api.app.wdesk.com/operations/128f274395254cf17eda6b3eb3d021b9"
}
Writing Values by A1 Range#
Use update values in a range when you prefer A1 notation.
Required scope: file:write
Warning: This endpoint overwrites the entire specified range. If the provided values array is smaller than the range, all cells not covered by the provided values will be cleared. Use
nullas a cell value to preserve an existing cell’s value.
PUT /spreadsheets/{spreadsheetId}/sheets/{sheetId}/values/{range}
Request Body:
{
"values": [
["Revenue", "Q1", "Q2"],
["Product A", 15000, 22000]
]
}
curl -X PUT "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/values/A1:C2" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Response (202 Accepted):
{
"operationLocation": "https://api.app.wdesk.com/operations/128f274395254cf17eda6b3eb3d021b9"
}
Important: Values are always written in Ones scale. If a cell is formatted to display in Thousands, writing
1500will display as1.5in that cell.
Applying Formats to Cells#
Use applyFormats in the update sheet content endpoint to apply cell formatting, text formatting, and value formatting to one or more ranges. The formats field accepts an array, so you can apply different formats to different ranges in a single request.
Important: The
formatsfield is an array of format objects, not a single object. Each element in the array specifies its ownrangesand format properties. This means you can format your header row, data cells, and totals row all in one API call. You do not need to make separate requests for each range or format type. See Understanding “One Update Field Per Request” for a full breakdown of this pattern.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Formatting Multiple Ranges in One Request#
This example applies three different format combinations in a single request:
Header row (row 0): blue background + bold text
Data cells (rows 1-9, columns 1-2): currency number format
Total row (row 10): bold text + bottom border via cell background
Request Body:
{
"applyFormats": {
"formats": [
{
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 2,
"stopRow": 0
}
],
"cellFormat": {
"backgroundColor": "#d0e0f0"
},
"textFormat": {
"bold": true
}
},
{
"ranges": [
{
"startColumn": 1,
"startRow": 1,
"stopColumn": 2,
"stopRow": 9
}
],
"valueFormat": {
"valueFormatType": "CURRENCY",
"showCurrencySymbol": true,
"showThousandsSeparator": true,
"precision": {
"auto": false,
"value": 2
},
"currencySymbol": {
"currency": {
"code": "USD",
"display": "SYMBOL"
}
}
}
},
{
"ranges": [
{
"startColumn": 0,
"startRow": 10,
"stopColumn": 2,
"stopRow": 10
}
],
"textFormat": {
"bold": true
},
"cellFormat": {
"backgroundColor": "#e8e8e8"
}
}
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Response (202 Accepted):
{
"operationLocation": "https://api.app.wdesk.com/operations/128f274395254cf17eda6b3eb3d021b9"
}
Format Object Properties#
Each element in the formats array can include any combination of these three format sub-objects. Omitted fields within each sub-object are left unchanged on the target cells.
Sub-object |
Controls |
Common Properties |
|---|---|---|
|
Cell appearance |
|
|
Text styling |
|
|
Number/date display |
|
Each format object also supports a clearValueFormatStyles boolean (default false). Set this to true when you change a cell’s valueFormatType and want to remove any value format styles left over from the previous type. For example, switching a cell from CURRENCY to PERCENT without clearing styles could leave currency-specific properties (like showCurrencySymbol) active.
Available valueFormatType values: AUTOMATIC, NUMBER, CURRENCY, ACCOUNTING, PERCENT, DATE, TEXT, PERIOD
Tip: Each format object in the array also requires a
rangesarray. A single format object can target multiple ranges by including multiple Range objects in itsrangesarray. This is useful when you want to apply the same format to non-contiguous areas.
Applying a Single Format#
If you only need to apply one format to one range, the formats array still requires an array, but it will contain just one element.
Request Body:
{
"applyFormats": {
"formats": [
{
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": null,
"stopRow": 0
}
],
"textFormat": {
"bold": true,
"fontSize": 12
}
}
]
}
}
Note: Setting
stopColumntonullmakes the range extend to the last column in the sheet. You can usenullon any Range field to make the range unbounded in that direction.
Applying Borders#
Use applyBorders to add borders to cell ranges. Like applyFormats, the borders field is an array, so you can define different border styles for different ranges in one request.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"applyBorders": {
"borders": [
{
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 2,
"stopRow": 0
}
],
"bottom": {
"color": "#000000",
"style": "SINGLE",
"weight": 2
}
},
{
"ranges": [
{
"startColumn": 0,
"startRow": 1,
"stopColumn": 2,
"stopRow": 9
}
],
"bottom": {
"color": "#cccccc",
"style": "DASHED1",
"weight": 1
},
"left": {
"color": "#cccccc",
"style": "SINGLE",
"weight": 1
},
"right": {
"color": "#cccccc",
"style": "SINGLE",
"weight": 1
}
}
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Response (202 Accepted):
{
"operationLocation": "https://api.app.wdesk.com/operations/128f274395254cf17eda6b3eb3d021b9"
}
Available border styles: SINGLE, DOUBLE, DASHED1, DASHED2, DASHED3, DASHED4, DASHED5
Border positions: top, bottom, left, right, diagonalUp, diagonalDown, innerHorizontal, innerVertical
Note: The
innerHorizontalandinnerVerticalpositions apply borders between cells within the range, not on the outer edges. Usetop,bottom,left,rightfor outer borders andinnerHorizontal,innerVerticalfor gridlines inside the range.
Clearing Formats and Borders#
Clearing Formats#
Use clearFormats to remove formatting from cells. You can clear specific format fields or use "*" to clear all fields in a category.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"clearFormats": {
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 5,
"stopRow": 20
}
],
"cellFormatFields": ["*"],
"textFormatFields": ["*"],
"valueFormatFields": ["*"],
"clearValueFormatStyles": true
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Tip: To clear only specific format properties, list them by name instead of using
"*". For example,"textFormatFields": ["bold", "italic"]clears only bold and italic without affecting font size, color, or other text formatting.
Note: Set
clearValueFormatStylestotruewhen clearingvalueFormatFieldsthat includevalueFormatType. Without this, cells may retain value format styles from the previous type. When cleared, cells revert to the Automatic value format with no styles.
Clearing Borders#
Use clearBorders to remove all borders from the specified ranges.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"clearBorders": {
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 5,
"stopRow": 20
}
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
Managing Rows and Columns#
All row and column operations use the update sheet content endpoint. Each operation uses intervals (0-indexed, inclusive start and end) to specify which rows or columns to affect.
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Inserting Rows#
Request Body:
{
"insertRows": {
"inheritFrom": "BEFORE",
"insertions": [
{ "index": 5, "count": 3 }
]
}
}
|
Behavior |
|---|---|
|
New rows inherit formatting from the row above the insertion point |
|
New rows inherit formatting from the row below the insertion point |
|
New rows have no formatting |
Inserting Columns#
Request Body:
{
"insertColumns": {
"inheritFrom": "BEFORE",
"insertions": [
{ "index": 2, "count": 1 }
]
}
}
Deleting Rows#
Request Body:
{
"deleteRows": {
"force": true,
"intervals": [
{ "start": 5, "end": 7 }
]
}
}
Warning: Setting
forcetotruedeletes the rows even if they contain source links, XBRL facts, or connections. Set tofalseto prevent deletion of rows containing these elements.
Deleting Columns#
Request Body:
{
"deleteColumns": {
"force": true,
"intervals": [
{ "start": 2, "end": 3 }
]
}
}
Hiding and Unhiding Rows#
Request Body (hide):
{
"hideRows": {
"force": true,
"intervals": [
{ "start": 7, "end": 9 }
]
}
}
Request Body (unhide):
{
"unhideRows": {
"intervals": [
{ "start": 7, "end": 9 }
]
}
}
Note: The
forcefield onhideRowsandhideColumnscontrols whether rows/columns containing footnotes can be hidden.
Hiding and Unhiding Columns#
Request Body (hide):
{
"hideColumns": {
"force": true,
"intervals": [
{ "start": 4, "end": 5 }
]
}
}
Request Body (unhide):
{
"unhideColumns": {
"intervals": [
{ "start": 4, "end": 5 }
]
}
}
Resizing Rows and Columns#
Resize to a specific size (in points):
Request Body (resize rows):
{
"resizeRows": {
"resizeIntervals": [
{
"intervals": [
{ "start": 0, "end": 0 }
],
"size": 32
}
]
}
}
Request Body (resize columns):
{
"resizeColumns": {
"resizeIntervals": [
{
"intervals": [
{ "start": 0, "end": 2 }
],
"size": 120
}
]
}
}
Auto-size to fit content:
Request Body (auto-fit columns):
{
"resizeColumnsToFit": {
"intervals": [
{ "start": 0, "end": 5 }
]
}
}
Request Body (auto-fit rows):
{
"resizeRowsToFit": {
"intervals": [
{ "start": 0, "end": 20 }
]
}
}
Note: The
sizefield for resizing is in points. Valid range is 3 to 10,000 points.
Merging and Unmerging Cells#
Merging Ranges#
Required scope: file:write
POST /spreadsheets/{spreadsheetId}/sheets/{sheetId}/update
Request Body:
{
"mergeRanges": {
"force": true,
"mergeType": "HORIZONTAL",
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 2,
"stopRow": 0
}
]
}
}
curl -X POST "https://api.app.wdesk.com/spreadsheets/${SPREADSHEET_ID}/sheets/${SHEET_ID}/update" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Version: 2026-01-01" \
-d @request.json
|
Behavior |
|---|---|
|
Merges cells horizontally across columns within each row |
|
Merges cells vertically across rows within each column |
|
Merges all cells in the range into a single cell |
Warning: Setting
forcetotruemerges even when cells contain data that would be lost. Whenforceisfalse, the operation fails if any non-primary cells in the merge range contain values.
Unmerging Ranges#
Request Body:
{
"unmergeRanges": {
"ranges": [
{
"startColumn": 0,
"startRow": 0,
"stopColumn": 2,
"stopRow": 0
}
]
}
}
Tip:
unmergeRangesunmerges any merges that intersect with the provided ranges, not just merges that are fully contained within them.
Polling for Completion#
All write operations (POST .../update, PUT .../values/{range}) return 202 Accepted with an operationLocation field in the response body and a Location header. Poll this URL until the operation completes.
Step 1 — Get the Operation Location#
The operationLocation field in the 202 response body contains the URL to poll. This is the same URL returned in the Location response header.
Step 2 — Poll Until Complete#
GET /operations/{operationId}
curl -X GET "https://api.app.wdesk.com/operations/{operationId}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Version: 2026-01-01"
Response (in progress):
{
"id": "<operationId>",
"status": "started",
"created": { "dateTime": "2026-01-15T10:00:00Z" },
"updated": { "dateTime": "2026-01-15T10:00:05Z" }
}
Response (completed):
{
"id": "<operationId>",
"status": "completed",
"resourceUrl": "https://api.app.wdesk.com/operations/<operationId>/results",
"created": { "dateTime": "2026-01-15T10:00:00Z" },
"updated": { "dateTime": "2026-01-15T10:00:30Z" }
}
Important: Always respect the
Retry-Afterresponse header when polling. The operations endpoint is rate-limited at approximately 1 request per second. Polling too frequently may result in429 Too Many Requestserrors.
Common Issues#
Issue |
Solution |
|---|---|
“Only one format applied per request” |
The |
“Values disappeared after PUT” |
|
“429 Too Many Requests when polling” |
Respect the |
“Scale mismatch in values” |
The values endpoint always uses Ones scale regardless of cell formatting. Writing |
“Which write endpoint should I use?” |
Use |
“Only one update field per request” |
Each |
“Borders not showing on inner cells” |
Use |
Summary of API Endpoints#
Operation |
Method |
Endpoint |
Required Scope |
|---|---|---|---|
Retrieve sheet data (with formatting) |
|
|
|
Retrieve range values (values only) |
|
|
|
Update values by range (A1 notation) |
|
|
|
Update sheet content (edit cells, apply formats, manage rows/columns, etc.) |
|
|
|
List sheets in a spreadsheet |
|
|
|
Poll async operation |
|
|
(same as originating request) |