Install
openclaw skills install google-apps-scriptGoogle Apps Script API integration with managed OAuth. Manage Apps Script projects, deployments, versions, and execute script functions. Use this skill when users want to create or update Apps Script projects, manage deployments and versions, run script functions remotely, or monitor script execution processes. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key.
openclaw skills install google-apps-scriptAccess the Google Apps Script API with managed OAuth authentication. Create and manage Apps Script projects, update script content, manage deployments and versions, execute functions remotely, and monitor script processes.
# Create a new Apps Script project
python <<'EOF'
import urllib.request, os, json
data = json.dumps({"title": "My Script"}).encode()
req = urllib.request.Request('https://api.maton.ai/google-apps-script/v1/projects', 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
https://api.maton.ai/google-apps-script/{native-api-path}
Maton proxies requests to script.googleapis.com and automatically injects your OAuth token.
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"
Manage your Google Apps Script OAuth connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=google-apps-script&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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'google-apps-script'}).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
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-apps-script",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
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
If you have multiple Google Apps Script connections, 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-apps-script/v1/processes')
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.
scripts.run) can have side effects. Always confirm with the user before running any script function.POST /google-apps-script/v1/projects
Content-Type: application/json
{
"title": "My Script Project",
"parentId": "{optional_drive_file_id}"
}
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Project name |
parentId | string | No | Drive ID of parent file (Sheet, Doc, Form, Slides). Omit for standalone projects |
Example:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({"title": "Analytics Helper"}).encode()
req = urllib.request.Request('https://api.maton.ai/google-apps-script/v1/projects', 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
Response:
{
"scriptId": "1e20iskkpOG79nb9sZz53XX6GmqEWwiLFd4GPoGsUL67N0lJXEu1FJud0",
"title": "Analytics Helper",
"createTime": "2026-05-05T09:28:57.482Z",
"updateTime": "2026-05-05T09:28:57.482Z",
"creator": {
"email": "user@example.com",
"name": "User"
},
"lastModifyUser": {
"email": "user@example.com",
"name": "User"
}
}
GET /google-apps-script/v1/projects/{scriptId}
GET /google-apps-script/v1/projects/{scriptId}/content
Optional Query Parameters:
| Parameter | Type | Description |
|---|---|---|
versionNumber | integer | Version to retrieve; omit for HEAD (latest) |
Response:
{
"scriptId": "...",
"files": [
{
"name": "appsscript",
"type": "JSON",
"source": "{\"timeZone\":\"America/New_York\",\"dependencies\":{},\"exceptionLogging\":\"STACKDRIVER\",\"runtimeVersion\":\"V8\"}",
"createTime": "2026-05-05T09:28:57.482Z",
"updateTime": "2026-05-05T09:28:57.482Z",
"functionSet": {}
},
{
"name": "Code",
"type": "SERVER_JS",
"source": "function myFunction() {\n return 'Hello';\n}",
"functionSet": {
"values": [{"name": "myFunction"}]
}
}
]
}
PUT /google-apps-script/v1/projects/{scriptId}/content
Content-Type: application/json
{
"files": [
{
"name": "appsscript",
"type": "JSON",
"source": "{\"timeZone\":\"America/New_York\",\"dependencies\":{},\"exceptionLogging\":\"STACKDRIVER\",\"runtimeVersion\":\"V8\"}"
},
{
"name": "Code",
"type": "SERVER_JS",
"source": "function myFunction() {\n Logger.log('Hello');\n return 'Hello';\n}"
}
]
}
File types: SERVER_JS (script code), HTML (HTML files), JSON (manifest only)
Important: This replaces ALL files in the project. Always include the appsscript manifest file.
Example:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"files": [
{
"name": "appsscript",
"type": "JSON",
"source": json.dumps({
"timeZone": "America/New_York",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
})
},
{
"name": "Code",
"type": "SERVER_JS",
"source": "function getData() {\n var sheet = SpreadsheetApp.getActiveSheet();\n return sheet.getDataRange().getValues();\n}"
}
]
}).encode()
req = urllib.request.Request('https://api.maton.ai/google-apps-script/v1/projects/{scriptId}/content', data=data, method='PUT')
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 /google-apps-script/v1/projects/{scriptId}/metrics?metricsGranularity=DAILY
Required Query Parameters:
| Parameter | Type | Description |
|---|---|---|
metricsGranularity | string | DAILY or WEEKLY |
Response:
{
"activeUsers": [
{"startTime": "2026-05-04T00:00:00Z", "endTime": "2026-05-05T00:00:00Z"}
],
"totalExecutions": [
{"startTime": "2026-05-04T00:00:00Z", "endTime": "2026-05-05T00:00:00Z"}
],
"failedExecutions": [
{"startTime": "2026-05-04T00:00:00Z", "endTime": "2026-05-05T00:00:00Z"}
]
}
POST /google-apps-script/v1/projects/{scriptId}/versions
Content-Type: application/json
{
"description": "Release v1.0"
}
Response:
{
"scriptId": "...",
"versionNumber": 1,
"description": "Release v1.0",
"createTime": "2026-05-05T09:29:20.755Z"
}
GET /google-apps-script/v1/projects/{scriptId}/versions
Optional Parameters:
| Parameter | Type | Description |
|---|---|---|
pageSize | integer | Max results per page |
pageToken | string | Token for next page |
Response:
{
"versions": [
{
"scriptId": "...",
"versionNumber": 1,
"description": "Release v1.0",
"createTime": "2026-05-05T09:29:20.755Z"
}
],
"nextPageToken": "..."
}
GET /google-apps-script/v1/projects/{scriptId}/versions/{versionNumber}
POST /google-apps-script/v1/projects/{scriptId}/deployments
Content-Type: application/json
{
"versionNumber": 1,
"description": "Production deployment",
"manifestFileName": "appsscript"
}
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
versionNumber | integer | No | Version to deploy |
description | string | No | Deployment description |
manifestFileName | string | No | Manifest file name (default: appsscript) |
Response:
{
"deploymentId": "AKfycbwcP87Ic2d91w3RqGX73ulArxNtrsJBUScaGZrPe45GztKsUo7b-CPHFr3aEmG9gIJxyg",
"deploymentConfig": {
"scriptId": "...",
"versionNumber": 1,
"manifestFileName": "appsscript",
"description": "Production deployment"
},
"updateTime": "2026-05-05T09:29:37.688Z"
}
GET /google-apps-script/v1/projects/{scriptId}/deployments
Optional Parameters:
| Parameter | Type | Description |
|---|---|---|
pageSize | integer | Max results per page |
pageToken | string | Token for next page |
GET /google-apps-script/v1/projects/{scriptId}/deployments/{deploymentId}
PUT /google-apps-script/v1/projects/{scriptId}/deployments/{deploymentId}
Content-Type: application/json
{
"deploymentConfig": {
"scriptId": "{scriptId}",
"versionNumber": 2,
"manifestFileName": "appsscript",
"description": "Updated to v2"
}
}
DELETE /google-apps-script/v1/projects/{scriptId}/deployments/{deploymentId}
GET /google-apps-script/v1/processes
Optional Parameters:
| Parameter | Type | Description |
|---|---|---|
pageSize | integer | Max results per page (default: 50) |
pageToken | string | Token for next page |
Response:
{
"processes": [
{
"projectName": "My Script",
"functionName": "myFunction",
"processType": "TIME_DRIVEN",
"processStatus": "COMPLETED",
"userAccessLevel": "READ",
"startTime": "2026-05-05T09:05:31.422Z",
"duration": "4.533s",
"runtimeVersion": "V8"
}
],
"nextPageToken": "..."
}
Process types: TIME_DRIVEN, EDITOR, SIMPLE_TRIGGER, INSTALLABLE_TRIGGER, WEBAPP, EXECUTION_API, ADD_ON, BATCH_TASK
Process statuses: COMPLETED, FAILED, TIMED_OUT, UNKNOWN, DELAYED, RUNNING, CANCELED
GET /google-apps-script/v1/processes:listScriptProcesses?scriptId={scriptId}
POST /google-apps-script/v1/scripts/{scriptId}:run
Content-Type: application/json
{
"function": "myFunction",
"parameters": ["arg1", 42],
"devMode": false
}
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
function | string | Yes | Function name to execute |
parameters | array | No | Function arguments (primitives only) |
devMode | boolean | No | If true, runs latest saved code instead of deployed version |
Response:
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.apps.script.v1.ExecutionResponse",
"result": "Hello World"
}
}
Note: Requires an "API Executable" deployment. The script must be deployed via Apps Script editor with "Deploy > New deployment > API Executable".
All list endpoints use token-based pagination:
GET /google-apps-script/v1/processes?pageSize=10&pageToken={nextPageToken}
Response includes nextPageToken when more results exist:
{
"processes": [...],
"nextPageToken": "Cg5iDAjLpuHPBhDQ1KO6Ag=="
}
const response = await fetch(
'https://api.maton.ai/google-apps-script/v1/projects',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: 'My Script' })
}
);
const project = await response.json();
console.log(project.scriptId);
import os
import requests
# Create a project
project = requests.post(
'https://api.maton.ai/google-apps-script/v1/projects',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={'title': 'My Script'}
).json()
# Update its content
requests.put(
f'https://api.maton.ai/google-apps-script/v1/projects/{project["scriptId"]}/content',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'files': [
{
'name': 'appsscript',
'type': 'JSON',
'source': '{"timeZone":"America/New_York","dependencies":{},"exceptionLogging":"STACKDRIVER","runtimeVersion":"V8"}'
},
{
'name': 'Code',
'type': 'SERVER_JS',
'source': 'function hello() { return "Hello World"; }'
}
]
}
)
scriptId is the Drive file ID of the Apps Script projectupdateContent replaces ALL files; always include the appsscript manifest filescripts.run endpoint requires an "API Executable" deployment configured in the Apps Script editordevMode: true in scripts.run executes the latest saved HEAD code (owner only)scripts.runmetricsGranularity query parameter (DAILY or WEEKLY)parentId during creationcurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Bad request (invalid argument, missing required fields) |
| 401 | Invalid or missing Maton API key |
| 403 | Forbidden (insufficient permissions for the script) |
| 404 | Script project or deployment not found |
| 409 | Conflict (concurrent edit) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Apps Script API |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
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
google-apps-script. For example:https://api.maton.ai/google-apps-script/v1/projectshttps://api.maton.ai/v1/projects