notion-sdk について
notion-sdkは、公式Python notion-client SDKを通じてNotionを自動化するスキルです。ページ作成、コンテンツブロック追加、データベース検索のスクリプトを備え、トークン検証とリトライ処理にも対応します。
主な機能
- 01ページとデータベース項目の作成
- 02書式付きコンテンツブロックの追加
- 03データベースの検索、絞り込み、並べ替え
- 04インテグレーショントークンの検証
- 05レート制限やサーバーエラー時の再試行
活用シーン
- 01PythonワークフローでのNotionページ作成
- 02ページへの構造化コンテンツの追加
- 03絞り込んだデータベースレコードの取得
- 04一時的なAPIエラーへの対処
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill notion-sdkインストール後、Claude Code で/notion-sdkを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/block-types.mdevolution-log.mdpagination.mdproperty-types.mdrich-text.mdscripts/add_blocks.pycreate_page.pynotion_wrapper.pyquery_database.pytests/test_block_builders.pytest_client.pytest_filter_builders.pytest_integration.pytest_property_builders.py詳細
Notion SDK スキル
公式の notion-client Python SDK を使用して、Notion をプログラムから操作します。最新バージョンは PyPI をご覧ください。
自己進化型スキル:このスキルは使用することで改善されます。手順に誤りがある場合、パラメーターに変更があった場合、または回避策が必要だった場合は、後回しにせず、すぐにこのファイルを修正してください。実際に再現できる問題がある場合にのみ更新してください。
このスキルを使用する場面
次のような場合にこのスキルを使用します。
- API 経由で Notion にページやデータベースを作成する
- Notion のデータベースをプログラムからクエリする
- Notion のページにブロック(テキスト、コード、見出し)を追加する
- Python で Notion のワークフローを自動化する
- 外部データソースを Notion と連携する
事前準備:トークンの取得
Notion API を操作する前に、インテグレーショントークンを取得します。
AskUserQuestion(questions=[{
"question": "Please provide your Notion Integration Token (starts with ntn_ or secret_)",
"header": "Notion Token",
"options": [
{"label": "I have a token ready", "description": "Token from notion.so/my-integrations"},
{"label": "Need to create one", "description": "Go to notion.so/my-integrations → New integration"}
],
"multiSelect": false
}])
ユーザーからトークンを受け取った後:
- 形式を検証します(
ntn_またはsecret_で始まる必要があります) scripts/notion_wrapper.pyのvalidate_token()でテストします- ユーザーに注意を促します:各ページ/データベースをインテグレーションと共有する必要があります
クイックスタート
1. データベースにページを作成する
from notion_client import Client
from scripts.create_page import (
create_database_page,
title_property,
status_property,
date_property,
)
client = Client(auth="ntn_...")
page = create_database_page(
client,
data_source_id="abc123...", # Database ID
properties={
"Name": title_property("My New Task"),
"Status": status_property("In Progress"),
"Due Date": date_property("2025-12-31"),
}
)
print(f"Created: {page['url']}")
2. コンテンツブロックを追加する
from scripts.add_blocks import (
append_blocks,
heading,
paragraph,
bullet,
code_block,
callout,
)
blocks = [
heading("Overview", level=2),
paragraph("This page was created via the Notion API."),
callout("Remember to share the page with your integration!", emoji="⚠️"),
heading("Tasks", level=3),
bullet("First task"),
bullet("Second task"),
code_block("print('Hello, Notion!')", language="python"),
]
append_blocks(client, page["id"], blocks)
3. データベースをクエリする
from scripts.query_database import (
query_data_source,
checkbox_filter,
status_filter,
and_filter,
sort_by_property,
)
# Find incomplete high-priority items
results = query_data_source(
client,
data_source_id="abc123...",
filter_obj=and_filter(
checkbox_filter("Done", False),
status_filter("Priority", "High")
),
sorts=[sort_by_property("Due Date", "ascending")]
)
for page in results:
title = page["properties"]["Name"]["title"][0]["plain_text"]
print(f"- {title}")
利用可能なスクリプト
| スクリプト | 用途 |
|---|---|
notion_wrapper.py | クライアントのセットアップ、トークンの検証、再試行ラッパー |
create_page.py | ページの作成、プロパティビルダー |
add_blocks.py | ブロックの追加、ブロックタイプビルダー |
query_database.py | クエリ、フィルター、並べ替え、検索 |
リファレンス
- プロパティタイプ - 例を含む全 24 種類のプロパティタイプ
- ブロックタイプ - 構造を含むすべてのブロックタイプ
- リッチテキスト - 書式設定、リンク、メンション
- ページネーション - 大きな結果セットの処理
重要な制約
レート制限
- 平均 毎秒 3 リクエスト(短時間のバーストは許容されます)
- レート制限を自動的に処理するには、
api_call_with_retry()を使用します - 429 レスポンスには
Retry-Afterヘッダーが含まれます
認証モデル
- ページ単位での共有が必要です(ワークスペース全体での共有ではありません)
- ユーザーは各ページ/データベースにインテグレーションを明示的に追加する必要があります:
- ページ → ... メニュー → コネクション → コネクションを追加 → インテグレーションを選択
API バージョン(v2.6.0+)
- 複数ソースのデータベースでは、
database_idの代わりにdata_source_idを使用します - シンプルなデータベースでは、従来の
database_idも引き続き使用できます - スクリプトは両方の形式を自動的に処理します
サポートされていない操作
- ワークスペース設定の変更
- ユーザー権限の管理
- テンプレートの作成/管理
- 請求/サブスクリプションへのアクセス
API の動作パターン
インテグレーションテストを通じて確認された知見です(検証用のテスト引用を記載)。
レート制限と再試行ロジック
api_call_with_retry() は一時的な障害を自動的に処理します。
| エラーの種類 | 動作 | 待機方法 |
|---|---|---|
| 429 レート制限 | 再試行します | Retry-After ヘッダーに従います(デフォルト 1 秒) |
| 500 サーバーエラー | 再試行します | 指数バックオフ:1 秒、2 秒、4 秒 |
| 認証/検証 | 直ちに失敗します | 再試行しません |
引用:test_client.py::TestRetryLogic(146~193 行目)
書き込み後の読み取り整合性
新しく作成したブロックは、すぐにクエリできない場合があります。最低 0.5 秒の遅延を設けてください。
append_blocks(client, page_id, blocks)
time.sleep(0.5) # Eventual consistency delay
children = client.blocks.children.list(page_id)
引用:test_integration.py::TestBlockAppend::test_retrieve_appended_blocks(298 行目)
v2.6.0 API の移行
| 旧パターン | 新パターン(v2.6.0+) |
|---|---|
client.databases.query() | client.data_sources.query() |
filter: {"value": "database"} | filter: {"value": "data_source"} |
引用:test_integration.py::TestDatabaseQuery(110 行目)
アーカイブのみ可能な削除
ページは API 経由で完全に削除することはできず、アーカイブ(ゴミ箱に移動)のみ可能です。
client.pages.update(page_id, archived=True) # Trash, not delete
引用:test_integration.py のクリーンアップ用フィクスチャ(72~76 行目)
エッジケースと検証
プロパティビルダーのエッジケース
| 入力 | 動作 | 有効? |
|---|---|---|
空文字列 "" | 空のコンテンツを作成 | はい |
空配列 [] | マルチセレクト/リレーションをクリア | はい |
数値に対する None | プロパティ値をクリア | はい |
ゼロ 0 | 有効な数値(falsy ではありません) | はい |
負数 -42 | 有効な数値 | はい |
| Unicode/絵文字 | 完全に保持されます | はい |
引用:test_property_builders.py::TestPropertyBuildersEdgeCases(302~341 行目)
入力検証の責任
ビルダーは意図的に寛容で、検証は API レベルで行われます。
| プロパティ | ビルダーが受け付ける値 | API による検証 |
|---|---|---|
| 日付 | 任意の文字列 | ISO 8601 のみ |
| URL | 任意の文字列 | 有効な URL 形式 |
| チェックボックス | 真偽値として評価される値 | ブール値が必要 |
ベストプラクティス:プロパティを作成する前に、アプリケーション内で検証してください。
引用:test_property_builders.py::TestPropertyBuildersInvalidInputs(347~376 行目)
トークンの検証
- 大文字と小文字を区別します。有効なのは小文字の
ntn_とsecret_のみです。 - API 呼び出し前に形式を確認します(不要なリクエストを節約できます)。
- 空または空白のみのトークンは即座に拒否されます。
引用:test_client.py::TestClientEdgeCases(196~224 行目)
クエリとフィルターのパターン
複合フィルターの構成
# Empty compound (matches all)
and_filter() # {"and": []}
# Deep nesting supported
and_filter(
or_filter(filter_a, filter_b),
and_filter(filter_c, filter_d)
)
引用:test_filter_builders.py::TestFilterEdgeCases(323~360 行目)
フィルターの制限
フィルターでは NULL プロパティは除外されないため、Python で確認してください。
if row["properties"]["Rating"]["number"] is not None:
# Process non-null values
引用:test_integration.py::TestDatabaseQuery::test_query_database_with_filter(120~135 行目)
ページネーションの不変条件
| 条件 | has_more | next_cursor |
|---|---|---|
| 結果がさらに存在する | True | 存在し、None ではない |
| これ以上結果がない | False | 存在しない場合/None の場合があります |
next_cursor を使用する前に、必ず has_more を確認してください。
引用:test_integration.py::TestDatabaseQuery::test_query_database_with_pagination(137~151 行目)
エラー処理
from notion_client import APIResponseError, APIErrorCode
try:
result = client.pages.create(...)
except APIResponseError as e:
if e.code == APIErrorCode.ObjectNotFound:
print("Page/database not found or not shared with integration")
elif e.code == APIErrorCode.Unauthorized:
print("Token invalid or expired")
elif e.code == APIErrorCode.RateLimited:
print(f"Rate limited. Retry after {e.additional_data.get('retry_after')}s")
else:
raise
インストール
uv pip install notion-client # v2.6+ required for data_source support
または、PEP 723 のインライン依存関係を使用してください(スクリプトに含めることができます)。
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
| オブジェクトが見つからない | ページがインテグレーションと共有されていない | ページを共有します:... メニュー → 接続 → インテグレーションを追加 |
| 認証されていない | トークンが無効または期限切れ | notion.so/my-integrations で新しいトークンを生成します |
| レート制限(429) | リクエストが多すぎる | 自動処理には api_call_with_retry() を使用します |
| クエリの結果が空 | フィルターに一致するものがない | フィルター構文とプロパティ名を確認します |
| 作成後にブロックが見つからない | 結果整合性の遅延 | 書き込み後、読み取り前に 0.5s の遅延を追加します |
| 無効なプロパティ型 | 誤ったビルダーを使用している | データベーススキーマでプロパティ型を確認します |
| トークン形式が拒否された | 接頭辞が正しくない(大文字と小文字を区別) | トークンは ntn_ または secret_(小文字)で始まる必要があります |
| データソース ID が機能しない | 古い API バージョン | notion-client を最新バージョンにアップグレードします |
実行後の振り返り
このスキルの実行後、終了する前に確認してください:
- コマンドは成功しましたか? — 失敗した場合は、失敗の原因となった指示またはエラーテーブルを修正します。
- パラメーターや出力に変更はありましたか? — 基盤となるツールのインターフェースに変更があった場合は、使用例とパラメーターテーブルを更新して一致させます。
- 回避策が必要でしたか? — 別のフラグや追加手順などで即興の対応が必要だった場合は、次回同じ回避策が不要になるよう、この SKILL.md を更新します。
問題が実際に発生し、再現可能な場合にのみ更新してください。推測で更新しないでください。