Назад към всички

baserow

// Baserow API integration with managed API key authentication. Manage database rows, fields, and tables. Use this skill when users want to read, create, update, or delete Baserow database rows, or query data with filters. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungk

$ git log --oneline --stat
stars:1,933
forks:367
updated:March 4, 2026
SKILL.mdreadonly
SKILL.md Frontmatter
namebaserow
descriptionBaserow API integration with managed API key authentication. Manage database rows, fields, and tables. Use this skill when users want to read, create, update, or delete Baserow database rows, or query data with filters. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
compatibilityRequires network access and valid Maton API key
metadata[object Object]

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://gateway.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://gateway.maton.ai/baserow/{native-api-path}

Replace {native-api-path} with the actual Baserow API endpoint path. The gateway 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

  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 Baserow API key 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=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://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))
EOF

Get 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": "90a5d047-b856-4577-ac05-faccaabf8989",
    "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://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))
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://gateway.maton.ai/baserow/api/database/rows/table/123/')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '90a5d047-b856-4577-ac05-faccaabf8989')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If omitted, the gateway uses the default (oldest) active connection.

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 of field_123 IDs
  • size - 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 fields
  • include - Comma-separated field names to include
  • exclude - 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://gateway.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://gateway.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://gateway.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

OperatorDescription
equalExact match
not_equalNot equal
containsContains substring
contains_notDoes not contain substring
contains_wordContains whole word
doesnt_contain_wordDoes not contain whole word
length_is_lower_thanText length is less than value

Numeric Filters

OperatorDescription
higher_thanGreater than
higher_than_or_equalGreater than or equal
lower_thanLess than
lower_than_or_equalLess than or equal
is_even_and_wholeValue is even and whole number

Date Filters

OperatorDescription
date_isDate equals (use with timezone)
date_is_notDate does not equal
date_is_beforeDate is before
date_is_on_or_beforeDate is on or before
date_is_afterDate is after
date_is_on_or_afterDate is on or after
date_is_withinDate is within period
date_equalDate equals (legacy)
date_not_equalDate does not equal (legacy)
date_equals_todayDate is today
date_before_todayDate is before today
date_after_todayDate is after today
date_within_daysDate within X days
date_within_weeksDate within X weeks
date_within_monthsDate within X months
date_equals_days_agoDate equals X days ago
date_equals_weeks_agoDate equals X weeks ago
date_equals_months_agoDate equals X months ago
date_equals_years_agoDate equals X years ago
date_equals_day_of_monthDate equals specific day of month
date_before_or_equalDate is before or equal (legacy)
date_after_or_equalDate is after or equal (legacy)

Boolean Filters

OperatorDescription
booleanBoolean equals (true/false)

Link Row Filters

OperatorDescription
link_row_hasHas linked row with ID
link_row_has_notDoes not have linked row with ID
link_row_containsLinked row contains text
link_row_not_containsLinked row does not contain text

Single Select Filters

OperatorDescription
single_select_equalSingle select equals option ID
single_select_not_equalSingle select does not equal option ID
single_select_is_any_ofSingle select is any of option IDs
single_select_is_none_ofSingle select is none of option IDs

Multiple Select Filters

OperatorDescription
multiple_select_hasHas option selected
multiple_select_has_notDoes not have option selected
multiple_select_is_exactlyExactly these options selected

Collaborator Filters

OperatorDescription
multiple_collaborators_hasHas collaborator
multiple_collaborators_has_notDoes not have collaborator

File Filters

OperatorDescription
filename_containsFile name contains
has_file_typeHas file of type (image, document)
files_lower_thanNumber of files less than

Empty/Not Empty Filters

OperatorDescription
emptyField is empty (value: true)
not_emptyField is not empty (value: true)

User Filters

OperatorDescription
user_isUser field equals user ID
user_is_notUser 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://gateway.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://gateway.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; use user_field_names=true for human-readable names
  • Row IDs are integers (not strings like Airtable's recXXX format)
  • 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

StatusNameDescription
200OkRequest completed successfully
204No ContentSuccess (for DELETE operations)
400Bad RequestThe request contains invalid values or the JSON could not be parsed
401UnauthorizedInvalid or missing database token
404Not FoundRow or table not found
413Request Entity Too LargeThe request exceeded the maximum allowed payload size
429Too Many RequestsRate limited (10 concurrent requests on cloud)
500Internal Server ErrorThe server encountered an unexpected condition
502Bad GatewayBaserow is restarting or an unexpected outage is in progress
503Service UnavailableThe server could not process your request in time

Troubleshooting: API Key Issues

  1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
  1. 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))
EOF

Troubleshooting: Invalid App Name

Ensure your URL path starts with baserow. For example:

  • Correct: https://gateway.maton.ai/baserow/api/database/rows/table/{table_id}/
  • Incorrect: https://gateway.maton.ai/api/database/rows/table/{table_id}/

Resources