通过托管 OAuth 代理网关对接 Airtable,对 Base、表和记录执行增删改查。
文档
Baserow
试用通过托管 API 密钥代理读写 Baserow 数据库,支持 CRUD、筛选与批量操作。
它能做什么
通过托管代理转发 Baserow API 请求,由网关自动注入令牌,原始凭证不暴露给调用方。支持行的完整 CRUD(单条与批量创建、更新、删除),以及字段、表的列表与查询。筛选覆盖文本、数值、日期运算符,排序与分页参数可配置。还支持行排序(move)与通过 URL 或 multipart 上传文件。所有写入操作执行前都必须获得用户明确确认。
什么时候用它
- 按筛选与排序条件读取 Baserow 表中的行
- 逐条或批量创建与更新数据行
- 列出表与字段以了解数据库结构
- 上传文件并附加到行的文件字段
技能文档
Baserow
Access the Baserow API with managed API key authentication. Manage database rows with full CRUD operations, filtering, sorting, and batch operations.
Quick Start
# List rows from a table
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/baserow/api/database/rows/table/{table_id}/?user_field_names=true')
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/baserow/{native-api-path}
Maton proxies requests to api.baserow.io and automatically injects your API 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
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your Baserow API key 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=baserow&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': 'baserow'}).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": "2026-03-02T12:01:29.812801Z",
"last_updated_time": "2026-03-02T12:02:17.932675Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "baserow",
"metadata": {},
"method": "API_KEY"
}
}
Open the returned url in a browser to enter your Baserow database token.
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 Baserow 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/baserow/api/database/rows/table/123/')
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 database rows, fields, and tables within the connected Baserow 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
Rows
List Rows
GET /baserow/api/database/rows/table/{table_id}/
Query parameters:
user_field_names=true- Use human-readable field names instead offield_123IDssize- Number of rows per page (default: 100)page- Page number (1-indexed)order_by- Field name to sort by (prefix with-for descending)filter__{field}__{operator}- Filter rows (see Filtering section)search- Search query across all fieldsinclude- Comma-separated field names to includeexclude- Comma-separated field names to exclude
Response:
{
"count": 5,
"next": "http://api.baserow.io/api/database/rows/table/123/?page=2&size=2",
"previous": null,
"results": [
{
"id": 1,
"order": "1.00000000000000000000",
"Assignee Name": "Alice Johnson",
"Email": "alice.johnson@example.com",
"Tasks": []
}
]
}
Get Row
GET /baserow/api/database/rows/table/{table_id}/{row_id}/
Response:
{
"id": 1,
"order": "1.00000000000000000000",
"field_7456198": "Alice Johnson",
"field_7456201": "alice.johnson@example.com",
"field_7456215": []
}
Create Row
POST /baserow/api/database/rows/table/{table_id}/
Content-Type: application/json
{
"field_7456198": "New User",
"field_7456201": "newuser@example.com"
}
Or with user field names:
POST /baserow/api/database/rows/table/{table_id}/?user_field_names=true
Content-Type: application/json
{
"Assignee Name": "New User",
"Email": "newuser@example.com"
}
Response:
{
"id": 6,
"order": "6.00000000000000000000",
"field_7456198": "New User",
"field_7456201": "newuser@example.com",
"field_7456215": []
}
Update Row
PATCH /baserow/api/database/rows/table/{table_id}/{row_id}/
Content-Type: application/json
{
"field_7456198": "Updated Name"
}
Response:
{
"id": 1,
"order": "1.00000000000000000000",
"field_7456198": "Updated Name",
"field_7456201": "alice.johnson@example.com",
"field_7456215": []
}
Delete Row
DELETE /baserow/api/database/rows/table/{table_id}/{row_id}/
Returns HTTP 204 No Content on success.
Batch Operations
Batch Create Rows
POST /baserow/api/database/rows/table/{table_id}/batch/
Content-Type: application/json
{
"items": [
{"field_7456198": "User 1", "field_7456201": "user1@example.com"},
{"field_7456198": "User 2", "field_7456201": "user2@example.com"}
]
}
Response:
{
"items": [
{"id": 7, "order": "7.00000000000000000000", "field_7456198": "User 1", ...},
{"id": 8, "order": "8.00000000000000000000", "field_7456198": "User 2", ...}
]
}
Batch Update Rows
PATCH /baserow/api/database/rows/table/{table_id}/batch/
Content-Type: application/json
{
"items": [
{"id": 7, "field_7456198": "Updated User 1"},
{"id": 8, "field_7456198": "Updated User 2"}
]
}
Response:
{
"items": [
{"id": 7, "order": "7.00000000000000000000", "field_7456198": "Updated User 1", ...},
{"id": 8, "order": "8.00000000000000000000", "field_7456198": "Updated User 2", ...}
]
}
Batch Delete Rows
POST /baserow/api/database/rows/table/{table_id}/batch-delete/
Content-Type: application/json
{
"items": [7, 8]
}
Returns HTTP 204 No Content on success.
Fields
List Fields
GET /baserow/api/database/fields/table/{table_id}/
Response:
[
{
"id": 7456198,
"table_id": 863922,
"name": "Assignee Name",
"order": 0,
"type": "text",
"primary": true,
"read_only": false,
"description": null
},
{
"id": 7456201,
"table_id": 863922,
"name": "Email",
"order": 1,
"type": "text",
"primary": false
}
]
Tables
List All Tables
Get all tables across all databases accessible by your token.
GET /baserow/api/database/tables/all-tables/
Response:
[
{
"id": 863922,
"name": "Assignees",
"order": 0,
"database_id": 419329
},
{
"id": 863923,
"name": "Tasks",
"order": 1,
"database_id": 419329
}
]
Move Row
Reposition a row within a table.
PATCH /baserow/api/database/rows/table/{table_id}/{row_id}/move/
Query parameters:
before_id- Row ID to move before (if omitted, moves to end)
Example - Move row to before row 3:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request(
'https://api.maton.ai/baserow/api/database/rows/table/863922/5/move/?before_id=3',
method='PATCH'
)
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"id": 5,
"order": "2.50000000000000000000",
"field_7456198": "Moved User",
"field_7456201": "moved@example.com"
}
File Uploads
Upload File via URL
Upload a file from a publicly accessible URL.
POST /baserow/api/user-files/upload-via-url/
Content-Type: application/json
{
"url": "https://example.com/image.png"
}
Example:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'url': 'https://httpbin.org/image/png'}).encode()
req = urllib.request.Request(
'https://api.maton.ai/baserow/api/user-files/upload-via-url/',
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:
{
"url": "https://files.baserow.io/user_files/...",
"thumbnails": {
"tiny": {"url": "...", "width": 21, "height": 21},
"small": {"url": "...", "width": 48, "height": 48},
"card_cover": {"url": "...", "width": 300, "height": 160}
},
"visible_name": "image.png",
"name": "abc123_image.png",
"size": 8090,
"mime_type": "image/png",
"is_image": true,
"image_width": 100,
"image_height": 100,
"uploaded_at": "2026-03-02T12:00:00Z"
}
Upload File (Multipart)
Upload a file directly using multipart form data.
POST /baserow/api/user-files/upload-file/
Content-Type: multipart/form-data
Example:
curl -X POST "https://api.maton.ai/baserow/api/user-files/upload-file/" \
-H "Authorization: Bearer $MATON_API_KEY" \
-F "file=@/path/to/file.pdf"
Response: Same format as upload-via-url.
Using Uploaded Files in Rows
After uploading, use the file object in a file field:
POST /baserow/api/database/rows/table/{table_id}/?user_field_names=true
Content-Type: application/json
{
"Attachment": [{"name": "abc123_image.png"}]
}
Filtering
Use filter parameters to query rows:
filter__{field}__{operator}={value}
With user_field_names=true:
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&filter__Assignee+Name__contains=Alice
Multiple filters use AND logic by default. Use filter_type=OR to change to OR logic.
Filter Operators
Text Filters
| Operator | Description |
|---|---|
equal | Exact match |
not_equal | Not equal |
contains | Contains substring |
contains_not | Does not contain substring |
contains_word | Contains whole word |
doesnt_contain_word | Does not contain whole word |
length_is_lower_than | Text length is less than value |
Numeric Filters
| Operator | Description |
|---|---|
higher_than | Greater than |
higher_than_or_equal | Greater than or equal |
lower_than | Less than |
lower_than_or_equal | Less than or equal |
is_even_and_whole | Value is even and whole number |
Date Filters
| Operator | Description |
|---|---|
date_is | Date equals (use with timezone) |
date_is_not | Date does not equal |
date_is_before | Date is before |
date_is_on_or_before | Date is on or before |
date_is_after | Date is after |
date_is_on_or_after | Date is on or after |
date_is_within | Date is within period |
date_equal | Date equals (legacy) |
date_not_equal | Date does not equal (legacy) |
date_equals_today | Date is today |
date_before_today | Date is before today |
date_after_today | Date is after today |
date_within_days | Date within X days |
date_within_weeks | Date within X weeks |
date_within_months | Date within X months |
date_equals_days_ago | Date equals X days ago |
date_equals_weeks_ago | Date equals X weeks ago |
date_equals_months_ago | Date equals X months ago |
date_equals_years_ago | Date equals X years ago |
date_equals_day_of_month | Date equals specific day of month |
date_before_or_equal | Date is before or equal (legacy) |
date_after_or_equal | Date is after or equal (legacy) |
Boolean Filters
| Operator | Description |
|---|---|
boolean | Boolean equals (true/false) |
Link Row Filters
| Operator | Description |
|---|---|
link_row_has | Has linked row with ID |
link_row_has_not | Does not have linked row with ID |
link_row_contains | Linked row contains text |
link_row_not_contains | Linked row does not contain text |
Single Select Filters
| Operator | Description |
|---|---|
single_select_equal | Single select equals option ID |
single_select_not_equal | Single select does not equal option ID |
single_select_is_any_of | Single select is any of option IDs |
single_select_is_none_of | Single select is none of option IDs |
Multiple Select Filters
| Operator | Description |
|---|---|
multiple_select_has | Has option selected |
multiple_select_has_not | Does not have option selected |
multiple_select_is_exactly | Exactly these options selected |
Collaborator Filters
| Operator | Description |
|---|---|
multiple_collaborators_has | Has collaborator |
multiple_collaborators_has_not | Does not have collaborator |
File Filters
| Operator | Description |
|---|---|
filename_contains | File name contains |
has_file_type | Has file of type (image, document) |
files_lower_than | Number of files less than |
Empty/Not Empty Filters
| Operator | Description |
|---|---|
empty | Field is empty (value: true) |
not_empty | Field is not empty (value: true) |
User Filters
| Operator | Description |
|---|---|
user_is | User field equals user ID |
user_is_not | User field does not equal user ID |
Filter Examples
Text contains:
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&filter__Name__contains=John
Date within last 7 days:
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&filter__Created__date_within_days=7
Multiple filters (AND):
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&filter__Status__single_select_equal=1&filter__Priority__higher_than=3
Multiple filters (OR):
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&filter_type=OR&filter__Status__equal=Active&filter__Status__equal=Pending
Sorting
Use order_by parameter:
# Sort ascending by field name
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&order_by=Assignee+Name
# Sort descending (prefix with -)
GET /baserow/api/database/rows/table/{table_id}/?user_field_names=true&order_by=-Assignee+Name
Pagination
Use size and page parameters:
GET /baserow/api/database/rows/table/{table_id}/?size=25&page=2
Response includes next and previous URLs:
{
"count": 100,
"next": "http://api.baserow.io/api/database/rows/table/123/?page=3&size=25",
"previous": "http://api.baserow.io/api/database/rows/table/123/?page=1&size=25",
"results": [...]
}
Code Examples
JavaScript
// List rows with user field names
const response = await fetch(
'https://api.maton.ai/baserow/api/database/rows/table/863922/?user_field_names=true',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data.results);
Python
import os
import requests
# Create a row
response = requests.post(
'https://api.maton.ai/baserow/api/database/rows/table/863922/?user_field_names=true',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'Assignee Name': 'New User',
'Email': 'newuser@example.com'
}
)
row = response.json()
print(f"Created row ID: {row['id']}")
Notes
- Connection uses API_KEY authentication (database token), not OAuth
- By default, fields are returned as
field_{id}format; useuser_field_names=truefor human-readable names - Row IDs are integers (not strings like Airtable's
recXXXformat) - Table IDs can be found in the Baserow UI URL or API documentation
- Database tokens grant access only to database row endpoints, not admin endpoints
- Cloud version has a limit of 10 concurrent API requests
Error Handling
| Status | Name | Description |
|---|---|---|
| 200 | Ok | Request completed successfully |
| 204 | No Content | Success (for DELETE operations) |
| 400 | Bad Request | The request contains invalid values or the JSON could not be parsed |
| 401 | Unauthorized | Invalid or missing database token |
| 404 | Not Found | Row or table not found |
| 413 | Request Entity Too Large | The request exceeded the maximum allowed payload size |
| 429 | Too Many Requests | Rate limited (10 concurrent requests on cloud) |
| 500 | Internal Server Error | The server encountered an unexpected condition |
| 502 | Bad Gateway | Baserow is restarting or an unexpected outage is in progress |
| 503 | Service Unavailable | The server could not process your request in time |
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- 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
Ensure your URL path starts with baserow. For example:
- Correct:
https://api.maton.ai/baserow/api/database/rows/table/{table_id}/ - Incorrect:
https://api.maton.ai/api/database/rows/table/{table_id}/
Resources
常见问题
- 如何进行身份验证?
- 在 Authorization 头中携带 Maton API 密钥,代理会自动注入 Baserow 令牌,调用方无需直接管理原始凭证。
- 支持哪些操作?
- 行的 CRUD(列表、获取、创建、更新、删除)、批量创建/更新/删除、字段列表、表列表、行移动,以及 URL 与 multipart 两种文件上传。
- 写入操作是否可以自动执行?
- 不可以。执行任何创建、更新、删除或批量写入前,都必须先获得用户明确确认。
相关技能
通过托管代理查询 Supabase 表、管理认证用户与存储资源。
通过托管 OAuth 网关管理 Coda 文档、页面、表格、行、公式与控件。
通过 Maton 网关以托管 OAuth 方式访问 Basecamp 4,管理项目、待办、日程、留言、文档与团队聊天。
通过托管 OAuth 接口查询和管理 Google BigQuery 数据集、表与作业。
通过托管 OAuth 网关访问 QuickBooks Online API,默认只读,写入需用户确认。