Coda
description: |
by byungkyu · published 2026-03-22
$ claw add gh:byungkyu/byungkyu-coda-api---
name: coda
description: |
Coda API integration with managed OAuth. Manage docs, pages, tables, rows, and formulas.
Use this skill when users want to read, create, update, or delete Coda docs, pages, tables, or rows.
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: 🧠
homepage: "https://maton.ai"
requires:
env:
- MATON_API_KEY
---
# Coda
Access the Coda API with managed OAuth authentication. Manage docs, pages, tables, rows, formulas, and controls with full CRUD operations.
Quick Start
# List your docs
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/coda/apis/v1/docs')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFBase URL
https://gateway.maton.ai/coda/apis/v1/{resource}Replace `{resource}` with the actual Coda API endpoint path. The gateway proxies requests to `coda.io/apis/v1` 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](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
Connection Management
Manage your Coda OAuth connections at `https://ctrl.maton.ai`.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=coda&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFCreate Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'coda'}).encode()
req = urllib.request.Request('https://ctrl.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))
EOFGet Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.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": "f46d34b1-3735-478a-a0d7-54115a16cd46",
"status": "ACTIVE",
"creation_time": "2026-02-12T01:38:10.500238Z",
"last_updated_time": "2026-02-12T01:38:33.545353Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "coda",
"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://ctrl.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))
EOFSpecifying Connection
If you have multiple Coda connections, specify which one to use with the `Maton-Connection` header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/coda/apis/v1/docs')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'f46d34b1-3735-478a-a0d7-54115a16cd46')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFIf omitted, the gateway uses the default (oldest) active connection.
API Reference
Account
#### Get Current User
GET /coda/apis/v1/whoamiReturns information about the authenticated user.
Docs
#### List Docs
GET /coda/apis/v1/docsQuery parameters:
#### Create Doc
POST /coda/apis/v1/docs
Content-Type: application/json
{
"title": "My New Doc",
"sourceDoc": "optional-source-doc-id",
"timezone": "America/Los_Angeles",
"folderId": "optional-folder-id"
}#### Get Doc
GET /coda/apis/v1/docs/{docId}#### Delete Doc
DELETE /coda/apis/v1/docs/{docId}Pages
#### List Pages
GET /coda/apis/v1/docs/{docId}/pagesQuery parameters:
#### Create Page
POST /coda/apis/v1/docs/{docId}/pages
Content-Type: application/json
{
"name": "New Page",
"subtitle": "Optional subtitle",
"parentPageId": "optional-parent-page-id"
}#### Get Page
GET /coda/apis/v1/docs/{docId}/pages/{pageIdOrName}#### Update Page
PUT /coda/apis/v1/docs/{docId}/pages/{pageIdOrName}
Content-Type: application/json
{
"name": "Updated Page Name",
"subtitle": "Updated subtitle"
}#### Delete Page
DELETE /coda/apis/v1/docs/{docId}/pages/{pageIdOrName}Tables
#### List Tables
GET /coda/apis/v1/docs/{docId}/tablesQuery parameters:
#### Get Table
GET /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}Columns
#### List Columns
GET /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/columnsQuery parameters:
#### Get Column
GET /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/columns/{columnIdOrName}Rows
#### List Rows
GET /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/rowsQuery parameters:
#### Get Row
GET /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/rows/{rowIdOrName}Query parameters:
#### Insert/Upsert Rows
POST /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/rows
Content-Type: application/json
{
"rows": [
{
"cells": [
{"column": "Column Name", "value": "Cell Value"},
{"column": "Another Column", "value": 123}
]
}
],
"keyColumns": ["Column Name"]
}#### Update Row
PUT /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/rows/{rowIdOrName}
Content-Type: application/json
{
"row": {
"cells": [
{"column": "Column Name", "value": "Updated Value"}
]
}
}#### Delete Row
DELETE /coda/apis/v1/docs/{docId}/tables/{tableIdOrName}/rows/{rowIdOrName}Formulas
#### List Formulas
GET /coda/apis/v1/docs/{docId}/formulas#### Get Formula
GET /coda/apis/v1/docs/{docId}/formulas/{formulaIdOrName}Controls
#### List Controls
GET /coda/apis/v1/docs/{docId}/controls#### Get Control
GET /coda/apis/v1/docs/{docId}/controls/{controlIdOrName}Permissions
#### Get Sharing Metadata
GET /coda/apis/v1/docs/{docId}/acl/metadata#### List Permissions
GET /coda/apis/v1/docs/{docId}/acl/permissions#### Add Permission
POST /coda/apis/v1/docs/{docId}/acl/permissions
Content-Type: application/json
{
"access": "readonly",
"principal": {
"type": "email",
"email": "user@example.com"
}
}Access values: `readonly`, `write`, `comment`
#### Delete Permission
DELETE /coda/apis/v1/docs/{docId}/acl/permissions/{permissionId}Categories
#### List Categories
GET /coda/apis/v1/categoriesUtilities
#### Resolve Browser Link
GET /coda/apis/v1/resolveBrowserLink?url={encodedUrl}Converts a Coda browser URL to API resource information.
#### Get Mutation Status
GET /coda/apis/v1/mutationStatus/{requestId}Check the status of an asynchronous mutation operation.
Analytics
#### List Doc Analytics
GET /coda/apis/v1/analytics/docsQuery parameters:
#### List Pack Analytics
GET /coda/apis/v1/analytics/packs#### Get Analytics Update Time
GET /coda/apis/v1/analytics/updatedPagination
Coda uses cursor-based pagination with `pageToken`:
GET /coda/apis/v1/docs?limit=25Response includes `nextPageToken` when more results exist:
{
"items": [...],
"href": "https://coda.io/apis/v1/docs?pageToken=...",
"nextPageToken": "eyJsaW1..."
}Use the `nextPageToken` value as `pageToken` in subsequent requests.
Asynchronous Mutations
Create, update, and delete operations return HTTP 202 with a `requestId`:
{
"id": "canvas-abc123",
"requestId": "mutate:9f038510-be42-4d16-bccf-3468d38efd57"
}Check mutation status:
GET /coda/apis/v1/mutationStatus/mutate:9f038510-be42-4d16-bccf-3468d38efd57Response:
{
"completed": true
}Mutations are generally processed within a few seconds.
Code Examples
JavaScript - List Docs
const response = await fetch(
'https://gateway.maton.ai/coda/apis/v1/docs?limit=10',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data.items);Python - List Docs
import os
import requests
response = requests.get(
'https://gateway.maton.ai/coda/apis/v1/docs',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'limit': 10}
)
data = response.json()
for doc in data['items']:
print(f"{doc['name']}: {doc['id']}")Python - Create Doc and Page
import os
import requests
headers = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
base_url = 'https://gateway.maton.ai/coda/apis/v1'
# Create doc
doc_response = requests.post(
f'{base_url}/docs',
headers=headers,
json={'title': 'My New Doc'}
)
doc = doc_response.json()
print(f"Created doc: {doc['id']}")
# Create page
page_response = requests.post(
f'{base_url}/docs/{doc["id"]}/pages',
headers=headers,
json={'name': 'First Page', 'subtitle': 'Created via API'}
)
page = page_response.json()
print(f"Created page: {page['id']}")Python - Insert Rows
import os
import requests
headers = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
response = requests.post(
'https://gateway.maton.ai/coda/apis/v1/docs/{docId}/tables/{tableId}/rows',
headers=headers,
json={
'rows': [
{
'cells': [
{'column': 'Name', 'value': 'John Doe'},
{'column': 'Email', 'value': 'john@example.com'}
]
}
]
}
)
result = response.json()
print(f"Request ID: {result['requestId']}")Notes
Rate Limits
| Operation | Limit |
|-----------|-------|
| Reading data | 100 requests per 6 seconds |
| Writing data | 10 requests per 6 seconds |
| Writing doc content | 5 requests per 10 seconds |
| Listing docs | 4 requests per 6 seconds |
| Reading analytics | 100 requests per 6 seconds |
Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Missing Coda connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found |
| 409 | Doc not yet accessible (just created) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Coda API |
Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
echo $MATON_API_KEY2. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.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))
EOFTroubleshooting: Invalid App Name
1. Ensure your URL path starts with `coda`. For example:
Resources
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...