v1.0.5

Notion

byungkyu byungkyu ← All skills

Notion API integration with managed OAuth. Query databases, create and update pages, manage blocks. Use this skill when users want to interact with Notion workspaces, databases, or pages. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).

Downloads
3.1k
Stars
2
Versions
6
Updated
2026-02-23

Install

npx clawhub@latest install notion-api-skill

Documentation

Notion

Access the Notion API with managed OAuth authentication. Query databases, create pages, manage blocks, and search your workspace.

Quick Start

Search for pages

python <<'EOF'

import urllib.request, os, json

data = json.dumps({'query': 'meeting notes'}).encode()

req = urllib.request.Request('https://gateway.maton.ai/notion/v1/search', data=data, method='POST')

req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')

req.add_header('Content-Type', 'application/json')

req.add_header('Notion-Version', '2025-09-03')

print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))

EOF

Base URL

https://gateway.maton.ai/notion/{native-api-path}

Replace {native-api-path} with the actual Notion API endpoint path. The gateway proxies requests to api.notion.com and automatically injects your OAuth token.

Required Headers

All Notion API requests require the version header:

Notion-Version: 2025-09-03

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 Notion 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=notion&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': 'notion'}).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": "21fd90f9-5935-43cd-b6c8-bde9d915ca80",

"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": "notion",

"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))

EOF

Specifying Connection

If you have multiple Notion connections, specify which one to use with the Maton-Connection header:

python <<'EOF'

import urllib.request, os, json

data = json.dumps({'query': 'meeting notes'}).encode()

req = urllib.request.Request('https://gateway.maton.ai/notion/v1/search', data=data, method='POST')

req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')

req.add_header('Content-Type', 'application/json')

req.add_header('Notion-Version', '2025-09-03')

req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')

print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))

EOF

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

Key Concept: Databases vs Data Sources

In API version 2025-09-03, databases and data sources are separate:

| Concept | Use For |

|---------|---------|

| Database | Creating databases, getting data source IDs |

| Data Source | Querying, updating schema, updating properties |

Use GET /databases/{id} to get the data_sources array, then use /data_sources/ endpoints:

{

"object": "database",

"id": "abc123",

"data_sources": [

{"id": "def456", "name": "My Database"}

]

}

API Reference

Search

Search for pages:

POST /notion/v1/search

Content-Type: application/json

Notion-Version: 2025-09-03

{

"query": "meeting notes",

"filter": {"property": "object", "value": "page"}

}

Search for data sources:

POST /notion/v1/search

Content-Type: application/json

Notion-Version: 2025-09-03

{

"filter": {"property": "object", "value": "data_source"}

}

Data Sources

#### Get Data Source

GET /notion/v1/data_sources/{dataSourceId}

Notion-Version: 2025-09-03

#### Query Data Source

POST /notion/v1/data_sources/{dataSourceId}/query

Content-Type: application/json

Notion-Version: 2025-09-03

{

"filter": {

"property": "Status",

"select": {"equals": "Active"}

},

"sorts": [

{"property": "Created", "direction": "descending"}

],

"page_size": 100

}

#### Update Data Source

PATCH /notion/v1/data_sources/{dataSourceId}

Content-Type: application/json

Notion-Version: 2025-09-03

{

"title": [{"type": "text", "text": {"content": "Updated Title"}}],

"properties": {

"NewColumn": {"rich_text": {}}

}

}

Databases

#### Get Database

GET /notion/v1/databases/{databaseId}

Notion-Version: 2025-09-03

#### Create Database

POST /notion/v1/databases

Content-Type: application/json

Notion-Version: 2025-09-03

{

"parent": {"type": "page_id", "page_id": "PARENT_PAGE_ID"},

"title": [{"type": "text", "text": {"content": "New Database"}}],

"properties": {

"Name": {"title": {}},

"Status": {"select": {"options": [{"name": "Active"}, {"name": "Done"}]}}

}

}

Pages

#### Get Page

GET /notion/v1/pages/{pageId}

Notion-Version: 2025-09-03

#### Create Page

POST /notion/v1/pages

Content-Type: application/json

Notion-Version: 2025-09-03

{

"parent": {"page_id": "PARENT_PAGE_ID"},

"properties": {

"title": {"title": [{"text": {"content": "New Page"}}]}

}

}

#### Create Page in Data Source

POST /notion/v1/pages

Content-Type: application/json

Notion-Version: 2025-09-03

{

"parent": {"data_source_id": "DATA_SOURCE_ID"},

"properties": {

"Name": {"title": [{"text": {"content": "New Page"}}]},

"Status": {"select": {"name": "Active"}}

}

}

#### Update Page Properties

PATCH /notion/v1/pages/{pageId}

Content-Type: application/json

Notion-Version: 2025-09-03

{

"properties": {

"Status": {"select": {"name": "Done"}}

}

}

#### Update Page Icon

PATCH /notion/v1/pages/{pageId}

Content-Type: application/json

Notion-Version: 2025-09-03

{

"icon": {"type": "emoji", "emoji": "🚀"}

}

#### Archive Page

PATCH /notion/v1/pages/{pageId}

Content-Type: application/json

Notion-Version: 2025-09-03

{

"archived": true

}

Blocks

#### Get Block Children

GET /notion/v1/blocks/{blockId}/children

Notion-Version: 2025-09-03

#### Append Block Children

PATCH /notion/v1/blocks/{blockId}/children

Content-Type: application/json

Notion-Version: 2025-09-03

{

"children": [

{

"object": "block",

"type": "paragraph",

"paragraph": {

"rich_text": [{"type": "text", "text": {"content": "New paragraph"}}]

}

}

]

}

#### Delete Block

DELETE /notion/v1/blocks/{blockId}

Notion-Version: 2025-09-03

Users

#### List Users

GET /notion/v1/users

Notion-Version: 2025-09-03

#### Get Current User

GET /notion/v1/users/me

Notion-Version: 2025-09-03

Filter Operators

  • -equals, does_not_equal
  • -contains, does_not_contain
  • -starts_with, ends_with
  • -is_empty, is_not_empty
  • -greater_than, less_than

Block Types

  • -paragraph, heading_1, heading_2, heading_3
  • -bulleted_list_item, numbered_list_item
  • -to_do, code, quote, divider

Code Examples

JavaScript

const response = await fetch('https://gateway.maton.ai/notion/v1/search', {

method: 'POST',

headers: {

'Content-Type': 'application/json',

'Authorization': Bearer ${process.env.MATON_API_KEY},

'Notion-Version': '2025-09-03'

},

body: JSON.stringify({ query: 'meeting' })

});

Python

import os

import requests

response = requests.post(

'https://gateway.maton.ai/notion/v1/search',

headers={

'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',

'Notion-Version': '2025-09-03'

},

json={'query': 'meeting'}

)

Notes

  • -All IDs are UUIDs (with or without hyphens)
  • -Use GET /databases/{id} to get the data_sources array containing data source IDs
  • -Creating databases requires POST /databases endpoint
  • -Delete blocks returns the block with archived: true
  • -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 Notion connection |

| 401 | Invalid or missing Maton API key |

| 429 | Rate limited (10 req/sec per account) |

| 4xx/5xx | Passthrough error from Notion 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://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

1. Ensure your URL path starts with notion. For example:

  • -Correct: https://gateway.maton.ai/notion/v1/search
  • -Incorrect: https://gateway.maton.ai/v1/search

Resources

  • -[Notion API Introduction](https://developers.notion.com/reference/intro)
  • -[Search](https://developers.notion.com/reference/post-search.md)
  • -[Query Database](https://developers.notion.com/reference/post-database-query.md)
  • -[Get Page](https://developers.notion.com/reference/retrieve-a-page.md)
  • -[Create Page](https://developers.notion.com/reference/post-page.md)
  • -[Update Page](https://developers.notion.com/reference/patch-page.md)
  • -[Append Block Children](https://developers.notion.com/reference/patch-block-children.md)
  • -[Filter Reference](https://developers.notion.com/reference/post-database-query-filter.md)
  • -[LLM Reference](https://developers.notion.com/llms.txt)
  • -[Maton Community](https://discord.com/invite/dBfFAcefs2)
  • -[Maton Support](mailto:support@maton.ai)

Launch an agent with Notion on Termo.