🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Google Sheets

by @byungkyu

Google Sheets API integration with managed OAuth. Read and write spreadsheet data, create sheets, apply formatting, and manage ranges. Use this skill when us...

Versionv1.0.8
Downloads15,013
Installs55
Stars⭐ 12
TERMINAL
clawhub install google-sheets

πŸ“– About This Skill


name: google-sheets description: | Google Sheets API integration with managed OAuth. Read and write spreadsheet data, create sheets, apply formatting, and manage ranges. Use this skill when users want to read from or write to Google Sheets. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 requires: env: - MATON_API_KEY

Google Sheets

Access the Google Sheets API with managed OAuth authentication. Read and write spreadsheet values, create sheets, apply formatting, and perform batch operations.

Quick Start

# Read values from a spreadsheet (note: range is URL-encoded)
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-sheets/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1%21A1%3AD10')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://api.maton.ai/google-sheets/{native-api-path}

Maton proxies requests to sheets.googleapis.com and automatically injects your OAuth token.

Authentication

All requests require the Maton API key in the Authorization header:

Authorization: Bearer $MATON_API_KEY

Environment Variable: Set your API key as MATON_API_KEY:

export MATON_API_KEY="YOUR_API_KEY"

Getting Your API Key

1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key

Connection Management

Manage your Google OAuth connections at https://api.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=google-sheets&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'google-sheets'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Get Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "connection": {
    "connection_id": "{connection_id}",
    "status": "ACTIVE",
    "creation_time": "2025-12-08T07:20:53.488460Z",
    "last_updated_time": "2026-01-31T20:03:32.593153Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "google-sheets",
    "metadata": {}
  }
}

Open the returned url in a browser to complete OAuth authorization.

Delete Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Specifying Connection

If you have multiple Google accounts connected, specify which one to use with the Maton-Connection header:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-sheets/v4/spreadsheets/SPREADSHEET_ID')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If you have multiple connections, always include this header to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to spreadsheets, sheets, cells, and data ranges within the connected Google Sheets account.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
  • API Reference

    Get Spreadsheet Metadata

    GET /google-sheets/v4/spreadsheets/{spreadsheetId}
    

    Get Values

    GET /google-sheets/v4/spreadsheets/{spreadsheetId}/values/{range}
    

    Example:

    GET /google-sheets/v4/spreadsheets/SHEET_ID/values/Sheet1%21A1%3AD10
    

    Get Multiple Ranges

    GET /google-sheets/v4/spreadsheets/{spreadsheetId}/values:batchGet?ranges=Sheet1%21A1%3AB10&ranges=Sheet2%21A1%3AC5
    

    Update Values

    PUT /google-sheets/v4/spreadsheets/{spreadsheetId}/values/{range}?valueInputOption=USER_ENTERED
    Content-Type: application/json

    { "values": [ ["A1", "B1", "C1"], ["A2", "B2", "C2"] ] }

    Append Values

    POST /google-sheets/v4/spreadsheets/{spreadsheetId}/values/{range}:append?valueInputOption=USER_ENTERED
    Content-Type: application/json

    { "values": [ ["New Row 1", "Data", "More Data"], ["New Row 2", "Data", "More Data"] ] }

    Batch Update Values

    POST /google-sheets/v4/spreadsheets/{spreadsheetId}/values:batchUpdate
    Content-Type: application/json

    { "valueInputOption": "USER_ENTERED", "data": [ {"range": "Sheet1!A1:B2", "values": [["A1", "B1"], ["A2", "B2"]]}, {"range": "Sheet1!D1:E2", "values": [["D1", "E1"], ["D2", "E2"]]} ] }

    Clear Values

    POST /google-sheets/v4/spreadsheets/{spreadsheetId}/values/{range}:clear
    

    Create Spreadsheet

    POST /google-sheets/v4/spreadsheets
    Content-Type: application/json

    { "properties": {"title": "New Spreadsheet"}, "sheets": [{"properties": {"title": "Sheet1"}}] }

    Batch Update (formatting, add sheets, etc.)

    POST /google-sheets/v4/spreadsheets/{spreadsheetId}:batchUpdate
    Content-Type: application/json

    { "requests": [ {"addSheet": {"properties": {"title": "New Sheet"}}} ] }

    Common batchUpdate Requests

    Update Cells with Formatting

    {
      "updateCells": {
        "rows": [
          {"values": [{"userEnteredValue": {"stringValue": "Name"}}, {"userEnteredValue": {"numberValue": 100}}]}
        ],
        "fields": "userEnteredValue",
        "start": {"sheetId": 0, "rowIndex": 0, "columnIndex": 0}
      }
    }
    

    Format Header Row (Bold + Background Color)

    {
      "repeatCell": {
        "range": {"sheetId": 0, "startRowIndex": 0, "endRowIndex": 1, "startColumnIndex": 0, "endColumnIndex": 3},
        "cell": {
          "userEnteredFormat": {
            "backgroundColor": {"red": 0.2, "green": 0.6, "blue": 0.9},
            "textFormat": {"bold": true}
          }
        },
        "fields": "userEnteredFormat(backgroundColor,textFormat)"
      }
    }
    

    Auto-Resize Columns

    {
      "autoResizeDimensions": {
        "dimensions": {"sheetId": 0, "dimension": "COLUMNS", "startIndex": 0, "endIndex": 3}
      }
    }
    

    Rename Sheet

    {
      "updateSheetProperties": {
        "properties": {"sheetId": 0, "title": "NewName"},
        "fields": "title"
      }
    }
    

    Insert Rows/Columns

    {
      "insertDimension": {
        "range": {"sheetId": 0, "dimension": "ROWS", "startIndex": 1, "endIndex": 3},
        "inheritFromBefore": true
      }
    }
    

    Sort Range

    {
      "sortRange": {
        "range": {"sheetId": 0, "startRowIndex": 1, "endRowIndex": 10, "startColumnIndex": 0, "endColumnIndex": 3},
        "sortSpecs": [{"dimensionIndex": 1, "sortOrder": "DESCENDING"}]
      }
    }
    

    Add Filter

    {
      "setBasicFilter": {
        "filter": {
          "range": {"sheetId": 0, "startRowIndex": 0, "endRowIndex": 100, "startColumnIndex": 0, "endColumnIndex": 5}
        }
      }
    }
    

    Delete Sheet

    {
      "deleteSheet": {"sheetId": 123456789}
    }
    

    Value Input Options

  • RAW - Values are stored as-is
  • USER_ENTERED - Values are parsed as if typed into the UI (formulas executed, numbers parsed)
  • Range Notation

  • Sheet1!A1:D10 - Specific range
  • Sheet1!A:D - Entire columns A through D
  • Sheet1!1:10 - Entire rows 1 through 10
  • Sheet1 - Entire sheet
  • A1:D10 - Range in first sheet
  • Code Examples

    JavaScript

    // Read values
    const response = await fetch(
      'https://api.maton.ai/google-sheets/v4/spreadsheets/SHEET_ID/values/Sheet1!A1:D10',
      {
        headers: {
          'Authorization': Bearer ${process.env.MATON_API_KEY}
        }
      }
    );

    // Write values await fetch( 'https://api.maton.ai/google-sheets/v4/spreadsheets/SHEET_ID/values/Sheet1!A1:B2?valueInputOption=USER_ENTERED', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': Bearer ${process.env.MATON_API_KEY} }, body: JSON.stringify({ values: [['A1', 'B1'], ['A2', 'B2']] }) } );

    Python

    import os
    import requests

    Read values

    response = requests.get( 'https://api.maton.ai/google-sheets/v4/spreadsheets/SHEET_ID/values/Sheet1!A1:D10', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} )

    Write values

    response = requests.put( 'https://api.maton.ai/google-sheets/v4/spreadsheets/SHEET_ID/values/Sheet1!A1:B2', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}, params={'valueInputOption': 'USER_ENTERED'}, json={'values': [['A1', 'B1'], ['A2', 'B2']]} )

    Notes

  • When using curl, ranges in URL paths must be URL-encoded (! -> %21, : -> %3A). JavaScript fetch and Python requests handle encoding automatically.
  • Use valueInputOption=USER_ENTERED to parse formulas and numbers
  • Delete spreadsheets via the Google Drive API, not Sheets API
  • Sheet IDs are numeric and found in the spreadsheet metadata
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.
  • Error Handling

    | Status | Meaning | |--------|---------| | 400 | Missing Google Sheets connection | | 401 | Invalid or missing Maton API key | | 429 | Rate limited (10 req/sec per account) | | 4xx/5xx | Passthrough error from Google Sheets API |

    Troubleshooting: API Key Issues

    1. Check that the MATON_API_KEY environment variable is set:

    echo $MATON_API_KEY
    

    2. Verify the API key is valid by listing connections:

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.maton.ai/connections')
    req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
    print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
    EOF
    

    Troubleshooting: Invalid App Name

    1. Ensure your URL path starts with google-sheets. For example:

  • Correct: https://api.maton.ai/google-sheets/v4/spreadsheets/SPREADSHEET_ID
  • Incorrect: https://api.maton.ai/v4/spreadsheets/SPREADSHEET_ID
  • Resources

  • Sheets API Overview
  • Get Spreadsheet
  • Create Spreadsheet
  • Batch Update
  • Batch Update Request Types
  • Get Values
  • Update Values
  • Append Values
  • Batch Get Values
  • Batch Update Values
  • Maton Community
  • Maton Support
  • πŸ’‘ Examples

    # Read values from a spreadsheet (note: range is URL-encoded)
    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.maton.ai/google-sheets/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1%21A1%3AD10')
    req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
    print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
    EOF
    

    πŸ“‹ Tips & Best Practices

  • When using curl, ranges in URL paths must be URL-encoded (! -> %21, : -> %3A). JavaScript fetch and Python requests handle encoding automatically.
  • Use valueInputOption=USER_ENTERED to parse formulas and numbers
  • Delete spreadsheets via the Google Drive API, not Sheets API
  • Sheet IDs are numeric and found in the spreadsheet metadata
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.