Back to Docs

Write API

Create, update, and delete data in your Google Sheets via API.

Write API

The Write API allows you to create, update, and delete rows in your Google Sheets programmatically. This enables you to use SheetsJSON as a complete backend for your applications.

Note: Write API is available on Pro plans and above. Upgrade your plan to enable write operations.

Overview

Operation Method Endpoint Description
Create POST /api/sheets/:account/:sheet Append one or more rows
Update PUT /api/sheets/:account/:sheet/:row Update a specific row
Delete DELETE /api/sheets/:account/:sheet/:row Delete a specific row

All write operations require authentication via API key.

Create Rows (POST)

Append one or more rows to your sheet.

POST /api/sheets/:account_slug/:sheet_slug

Request Body

You can send either a single object or an array of objects:

Single row:

{
  "name": "Alice Johnson",
  "email": "[email protected]",
  "role": "Developer"
}

Multiple rows:

[
  {"name": "Alice Johnson", "email": "[email protected]", "role": "Developer"},
  {"name": "Bob Smith", "email": "[email protected]", "role": "Designer"}
]

Code Examples

```bash # Add a single row curl -X POST "https://api.sheetsjson.com/api/sheets/your-account/products" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "New Product", "price": "29.99", "category": "Electronics"}' # Add multiple rows curl -X POST "https://api.sheetsjson.com/api/sheets/your-account/products" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[{"name": "Product A", "price": "19.99"}, {"name": "Product B", "price": "39.99"}]' ```
```javascript // Using fetch API const response = await fetch( 'https://api.sheetsjson.com/api/sheets/your-account/products', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'New Product', price: '29.99', category: 'Electronics' }) } ); const data = await response.json(); console.log(data); // { success: true, message: "1 row(s) added", rows_added: 1 } // Adding multiple rows const multiResponse = await fetch( 'https://api.sheetsjson.com/api/sheets/your-account/products', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify([ { name: 'Product A', price: '19.99' }, { name: 'Product B', price: '39.99' } ]) } ); ```
```python import requests # Add a single row response = requests.post( 'https://api.sheetsjson.com/api/sheets/your-account/products', headers={ 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, json={ 'name': 'New Product', 'price': '29.99', 'category': 'Electronics' } ) print(response.json()) # {'success': True, 'message': '1 row(s) added', 'rows_added': 1} # Add multiple rows response = requests.post( 'https://api.sheetsjson.com/api/sheets/your-account/products', headers={'Authorization': 'Bearer YOUR_API_KEY'}, json=[ {'name': 'Product A', 'price': '19.99'}, {'name': 'Product B', 'price': '39.99'} ] ) ```

Response

Success (201 Created):

{
  "success": true,
  "message": "2 row(s) added",
  "rows_added": 2
}

Notes

  • Keys in your JSON must match the column headers in your sheet (case-insensitive)
  • New rows are always appended to the end of the sheet
  • Missing fields will result in empty cells
  • Extra fields not matching any column header will be ignored

Update Row (PUT)

Update an existing row by its row number.

PUT /api/sheets/:account_slug/:sheet_slug/:row_number

The :row_number is the 1-based row index in your sheet (row 1 is typically headers, so data starts at row 2).

Request Body

Send only the fields you want to update:

{
  "price": "34.99",
  "in_stock": "true"
}

Code Examples

```bash # Update row 5 curl -X PUT "https://api.sheetsjson.com/api/sheets/your-account/products/5" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"price": "34.99", "in_stock": "true"}' ```
```javascript const rowNumber = 5; const response = await fetch( `https://api.sheetsjson.com/api/sheets/your-account/products/${rowNumber}`, { method: 'PUT', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ price: '34.99', in_stock: 'true' }) } ); const data = await response.json(); console.log(data); // { success: true, message: "Row 5 updated", row: 5 } ```
```python import requests row_number = 5 response = requests.put( f'https://api.sheetsjson.com/api/sheets/your-account/products/{row_number}', headers={'Authorization': 'Bearer YOUR_API_KEY'}, json={ 'price': '34.99', 'in_stock': 'true' } ) print(response.json()) # {'success': True, 'message': 'Row 5 updated', 'row': 5} ```

Response

Success (200 OK):

{
  "success": true,
  "message": "Row 5 updated",
  "row": 5
}

Notes

  • Row numbers are 1-based (header row is row 1)
  • You cannot update row 1 (the header row)
  • Only specified fields are updated; other fields remain unchanged
  • Use the GET endpoint first to find the row number you want to update

Delete Row (DELETE)

Delete a row by its row number.

DELETE /api/sheets/:account_slug/:sheet_slug/:row_number

Code Examples

```bash # Delete row 5 curl -X DELETE "https://api.sheetsjson.com/api/sheets/your-account/products/5" \ -H "Authorization: Bearer YOUR_API_KEY" ```
```javascript const rowNumber = 5; const response = await fetch( `https://api.sheetsjson.com/api/sheets/your-account/products/${rowNumber}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const data = await response.json(); console.log(data); // { success: true, message: "Row 5 deleted", row: 5 } ```
```python import requests row_number = 5 response = requests.delete( f'https://api.sheetsjson.com/api/sheets/your-account/products/{row_number}', headers={'Authorization': 'Bearer YOUR_API_KEY'} ) print(response.json()) # {'success': True, 'message': 'Row 5 deleted', 'row': 5} ```

Response

Success (200 OK):

{
  "success": true,
  "message": "Row 5 deleted",
  "row": 5
}

Notes

  • Row numbers are 1-based (header row is row 1)
  • You cannot delete row 1 (the header row)
  • After deletion, subsequent rows shift up (row 6 becomes row 5, etc.)
  • This operation cannot be undone via the API

Error Responses

Write operations can return these specific errors:

Status Code Description
400 invalid_body Request body is not valid JSON or wrong format
400 invalid_row_number Row number is not a valid positive integer > 1
400 missing_headers Could not read sheet headers
401 api_key_required API key not provided
403 invalid_api_key API key is invalid
403 write_api_not_enabled Plan doesn’t include Write API
404 account_not_found Account slug not found
404 sheet_not_found Sheet slug not found
429 rate_limited Too many requests
502 google_api_error Error communicating with Google Sheets

Example Error Response

{
  "error": "Write API is not enabled for your plan. Please upgrade to Pro or higher.",
  "code": "write_api_not_enabled"
}

Best Practices

1. Validate Data Client-Side

Always validate your data before sending it to the API to avoid unnecessary requests:

function validateProduct(product) {
  if (!product.name || product.name.trim() === '') {
    throw new Error('Product name is required');
  }
  if (product.price && isNaN(parseFloat(product.price))) {
    throw new Error('Price must be a number');
  }
  return true;
}

2. Use Transactions for Related Updates

When updating multiple related rows, handle failures gracefully:

async function updateProducts(updates) {
  const results = [];
  for (const { row, data } of updates) {
    try {
      const response = await updateRow(row, data);
      results.push({ row, success: true, response });
    } catch (error) {
      results.push({ row, success: false, error: error.message });
    }
  }
  return results;
}

3. Implement Retry Logic

Handle transient errors with exponential backoff:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }
    
    return response;
  }
  throw new Error('Max retries exceeded');
}

4. Cache Read Data

When you need to update specific rows, cache the row numbers from your initial read:

// Build a lookup table from your data
const rows = await fetchProducts();
const rowLookup = new Map(
  rows.data.map((item, index) => [item.id, index + 2]) // +2 for header row
);

// Later, update by ID
const rowNumber = rowLookup.get('product-123');
await updateRow(rowNumber, { price: '49.99' });

Rate Limits

Write operations count against your API rate limits. See Rate Limits for details on limits by plan.

Plan Requests/minute Requests/day
Pro 300 50,000
Business 1,000 500,000
Enterprise Custom Custom

What’s Next?

Was this page helpful? |