Skill: ivangdavila/notion-api-integration (version 1.0.2)

--- name: Notion API Integration slug: notion-api-integration version: 1.0.2 homepage: https://clawic.com/skills/notion-api-integration description: Complete Notion API for databases, pages, blocks, users, search, comments, and property types with pagination and error handling. changelog: Fixed memory template to use standard status values and natural language context. metadata: {"clawdbot":{"emoji":"N","requires":{"env":["NOTION_API_KEY"],"config":["~/notion-api-integration/"]},"primaryEnv":"NOTION_API_KEY","os":["linux","darwin","win32"]}} --- # Notion API Integration Complete Notion API reference. See auxiliary files for detailed operations. ## Quick Start ```bash curl 'https://api.notion.com/v1/users/me' \ -H "Authorization: Bearer $NOTION_API_KEY" \ -H "Notion-Version: 2022-06-28" ``` ## Setup On first use, read `setup.md`. Preferences stored in `~/notion-api-integration/memory.md`. ## When to Use Any Notion operation: databases, pages, blocks, users, search, comments, properties. ## Architecture ``` ~/notion-api-integration/ ├── memory.md # Workspace context └── databases.md # Tracked database IDs ``` ## Quick Reference | Topic | File | |-------|------| | Setup and memory | `setup.md`, `memory-template.md` | | Databases: query, create, update | `databases.md` | | Pages: CRUD, properties | `pages.md` | | Blocks: content, children | `blocks.md` | | Property types reference | `properties.md` | | Filters and sorts | `filters.md` | | Search and users | `search.md` | | Pagination patterns | `pagination.md` | | Error handling | `errors.md` | ## Core Rules 1. **API version header required** - Always include `Notion-Version: 2022-06-28` (or newer) 2. **Bearer token auth** - `Authorization: Bearer $NOTION_API_KEY` 3. **Page IDs without dashes** - Remove dashes from URLs: `abc123def456` not `abc-123-def-456` 4. **Property names are case-sensitive** - Match exactly as defined in database 5. **Pagination mandatory** - Use `start_cursor` for results over 100 items 6. **Rate limits** - 3 requests/second average, burst allowed 7. **Integration access** - Pages must be shared with integration to access ## Authentication **Required environment variable:** - `NOTION_API_KEY` - Internal integration token (starts with `ntn_` or `secret_`) ```bash # All requests require these headers curl 'https://api.notion.com/v1/...' \ -H "Authorization: Bearer $NOTION_API_KEY" \ -H "Notion-Version: 2022-06-28" \ -H "Content-Type: application/json" ``` ## Common Traps - Missing `Notion-Version` header - 400 error - Page ID with dashes - 404 not found - Property name mismatch - Silent failure or error - Skipping pagination - Miss data beyond first 100 - No integration access - 404 even if page exists ## External Endpoints | Endpoint | Purpose | |----------|---------| | `https://api.notion.com/v1/*` | All Notion API operations | No other endpoints are accessed. ## Security & Privacy **Environment variable used:** - `NOTION_API_KEY` - for API authentication **Sent to Notion:** Database queries, page content, block updates via api.notion.com **Stays local:** API key (in environment variable only), ~/notion-api-integration/ preferences **Never:** Store API keys in files, access pages not shared with integration ## Scope This skill ONLY: - Makes requests to api.notion.com endpoints - Stores preferences in `~/notion-api-integration/` - Provides curl and code examples This skill NEVER: - Accesses files outside `~/notion-api-integration/` - Makes requests to other endpoints - Stores API keys in files ## Trust By using this skill, data is sent to Notion (notion.com). Only install if you trust Notion with your workspace data. ## Related Skills Install with `clawhub install <slug>` if user confirms: - `api` — REST API patterns - `pkm` — Personal knowledge management - `productivity` — Task and productivity workflows ## Feedback - If useful: `clawhub star notion-api-integration` - Stay updated: `clawhub sync`

path: blocks.md
content: # Blocks - Notion API

## Get Block Children

```bash
curl 'https://api.notion.com/v1/blocks/BLOCK_OR_PAGE_ID/children?page_size=100' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

## Append Children

```bash
curl -X PATCH 'https://api.notion.com/v1/blocks/BLOCK_OR_PAGE_ID/children' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "children": [
      {"object": "block", "type": "paragraph", "paragraph": {
        "rich_text": [{"type": "text", "text": {"content": "New paragraph"}}]
      }}
    ]
  }'
```

## Block Types

### Paragraph
```json
{"type": "paragraph", "paragraph": {"rich_text": [{"type": "text", "text": {"content": "Text"}}]}}
```

### Headings
```json
{"type": "heading_1", "heading_1": {"rich_text": [{"type": "text", "text": {"content": "H1"}}]}}
```
Also: `heading_2`, `heading_3`

### Lists
```json
{"type": "bulleted_list_item", "bulleted_list_item": {"rich_text": [{"type": "text", "text": {"content": "Item"}}]}}
{"type": "numbered_list_item", "numbered_list_item": {"rich_text": [{"type": "text", "text": {"content": "Item"}}]}}
```

### To-Do
```json
{"type": "to_do", "to_do": {"rich_text": [{"type": "text", "text": {"content": "Task"}}], "checked": false}}
```

### Code
```json
{"type": "code", "code": {"rich_text": [{"type": "text", "text": {"content": "code"}}], "language": "javascript"}}
```

### Quote / Callout
```json
{"type": "quote", "quote": {"rich_text": [{"type": "text", "text": {"content": "Quote"}}]}}
{"type": "callout", "callout": {"rich_text": [{"type": "text", "text": {"content": "Note"}}], "icon": {"type": "emoji", "emoji": "💡"}}}
```

### Divider
```json
{"type": "divider", "divider": {}}
```

## Update Block

```bash
curl -X PATCH 'https://api.notion.com/v1/blocks/BLOCK_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"paragraph": {"rich_text": [{"type": "text", "text": {"content": "Updated"}}]}}'
```

## Delete Block

```bash
curl -X DELETE 'https://api.notion.com/v1/blocks/BLOCK_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

## Rich Text Formatting

```json
{
  "type": "text",
  "text": {"content": "Styled", "link": {"url": "https://example.com"}},
  "annotations": {"bold": true, "italic": false, "code": false, "color": "red"}
}
```
Colors: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`, plus `_background` variants.


path: databases.md
content: # Databases - Notion API

## Query Database

```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"page_size": 100}'
```

### With Filter

```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "property": "Status",
      "status": {"equals": "Done"}
    }
  }'
```

### With Sort

```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "sorts": [{"property": "Due Date", "direction": "ascending"}]
  }'
```

## Retrieve Database

```bash
curl 'https://api.notion.com/v1/databases/DATABASE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

## Create Database

```bash
curl -X POST 'https://api.notion.com/v1/databases' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"type": "page_id", "page_id": "PARENT_PAGE_ID"},
    "title": [{"type": "text", "text": {"content": "My Database"}}],
    "properties": {
      "Name": {"title": {}},
      "Status": {"select": {"options": [
        {"name": "To Do", "color": "gray"},
        {"name": "Done", "color": "green"}
      ]}}
    }
  }'
```

## Update Database

```bash
curl -X PATCH 'https://api.notion.com/v1/databases/DATABASE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "title": [{"text": {"content": "Updated Name"}}]
  }'
```

## List All Databases

```bash
curl -X POST 'https://api.notion.com/v1/search' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"filter": {"value": "database", "property": "object"}}'
```

## Database ID from URL

URL: `https://notion.so/workspace/abc123def456?v=...`
Database ID: `abc123def456` (remove dashes if present)


path: errors.md
content: # Error Handling - Notion API

## Error Response Format

```json
{
  "object": "error",
  "status": 400,
  "code": "validation_error",
  "message": "Description"
}
```

## Common Errors

### 400 Bad Request

| Code | Cause | Fix |
|------|-------|-----|
| `invalid_json` | Malformed JSON | Validate syntax |
| `invalid_request` | Missing field | Check body |
| `validation_error` | Invalid value | Check types |

### 401 Unauthorized

| Code | Cause | Fix |
|------|-------|-----|
| `unauthorized` | Invalid token | Check API key |

### 404 Not Found

| Code | Cause | Fix |
|------|-------|-----|
| `object_not_found` | Page doesn't exist | Verify ID |
| | Not shared | Share with integration |
| | ID has dashes | Remove dashes |

### 429 Rate Limited

| Code | Cause | Fix |
|------|-------|-----|
| `rate_limited` | Too many requests | Wait and retry |

Rate limits: 3 requests/second average

### 500+ Server Error

| Code | Cause | Fix |
|------|-------|-----|
| `internal_server_error` | Notion issue | Retry later |

## Retry Strategy

```python
import time

def notion_request(method, url, **kwargs):
    max_retries = 3
    
    for attempt in range(max_retries):
        response = requests.request(method, url, **kwargs)
        
        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 2 ** attempt))
            time.sleep(retry_after)
            continue
        
        if response.status_code >= 500:
            time.sleep(2 ** attempt)
            continue
        
        return response
    
    raise Exception("Max retries exceeded")
```

## Common Mistakes

### Missing Notion-Version Header
```
400: Notion-Version header is required
```
Fix: Add `-H "Notion-Version: 2022-06-28"`

### Page ID with Dashes
```
404: object_not_found
```
URL: `Page-abc-123-def-456` -> ID: `abc123def456`

### Property Name Mismatch
```
400: Property 'status' not found
```
Property names are case-sensitive. Use exact name.

### Unshared Page
```
404: object_not_found
```
Integration can only access shared pages.

## Debugging Tips

1. Check full error response
2. Test token with `/v1/users/me`
3. Verify page is shared
4. Remove dashes from IDs
5. Match property types exactly


path: filters.md
content: # Filters and Sorts - Notion API

## Text Filter
```json
{"filter": {"property": "Name", "rich_text": {"contains": "search term"}}}
```
Operations: `equals`, `does_not_equal`, `contains`, `does_not_contain`, `starts_with`, `ends_with`, `is_empty`, `is_not_empty`

## Number Filter
```json
{"filter": {"property": "Price", "number": {"greater_than": 100}}}
```
Operations: `equals`, `does_not_equal`, `greater_than`, `less_than`, `greater_than_or_equal_to`, `less_than_or_equal_to`, `is_empty`, `is_not_empty`

## Select Filter
```json
{"filter": {"property": "Status", "select": {"equals": "Done"}}}
```

## Multi-Select Filter
```json
{"filter": {"property": "Tags", "multi_select": {"contains": "Important"}}}
```

## Status Filter
```json
{"filter": {"property": "Status", "status": {"equals": "In Progress"}}}
```

## Date Filter
```json
{"filter": {"property": "Due Date", "date": {"on_or_after": "2025-01-01"}}}
```
Operations: `equals`, `before`, `after`, `on_or_before`, `on_or_after`, `is_empty`, `is_not_empty`, `past_week`, `past_month`, `next_week`, `next_month`, `this_week`

## Checkbox Filter
```json
{"filter": {"property": "Done", "checkbox": {"equals": true}}}
```

## People Filter
```json
{"filter": {"property": "Assignee", "people": {"contains": "USER_ID"}}}
```

## Compound Filters

### AND
```json
{"filter": {"and": [
  {"property": "Status", "status": {"equals": "In Progress"}},
  {"property": "Priority", "select": {"equals": "High"}}
]}}
```

### OR
```json
{"filter": {"or": [
  {"property": "Status", "status": {"equals": "Done"}},
  {"property": "Status", "status": {"equals": "Archived"}}
]}}
```

## Sorts

### Single Sort
```json
{"sorts": [{"property": "Due Date", "direction": "ascending"}]}
```

### Multiple Sorts
```json
{"sorts": [
  {"property": "Priority", "direction": "descending"},
  {"property": "Due Date", "direction": "ascending"}
]}
```

### Sort by Timestamp
```json
{"sorts": [{"timestamp": "last_edited_time", "direction": "descending"}]}
```

## Full Query Example

```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {"and": [
      {"property": "Status", "status": {"does_not_equal": "Done"}},
      {"property": "Due Date", "date": {"on_or_before": "2025-01-31"}}
    ]},
    "sorts": [{"property": "Due Date", "direction": "ascending"}],
    "page_size": 100
  }'
```


path: memory-template.md
content: # Memory Template — Notion API

Create `~/notion-api-integration/memory.md` with this structure:

```markdown
# Notion Memory

## Status
status: ongoing
version: 1.0.0
last: YYYY-MM-DD
integration: pending | done | declined

## Context
<!-- What you know about their Notion workspace -->
<!-- Workspace name if shared -->
<!-- Main databases they work with and their purposes -->
<!-- Common operations they request -->

## Databases
<!-- Key databases they've mentioned or queried -->
<!-- Format: db_XXX: Database Name (purpose) -->

## Notes
<!-- Internal observations -->
<!-- Property names they use frequently -->
<!-- Any pagination patterns or preferences -->

---
*Updated: YYYY-MM-DD*
```

## Status Values

| Value | Meaning | Behavior |
|-------|---------|----------|
| `ongoing` | Still learning | Ask questions when relevant |
| `complete` | Has enough context | Work normally |
| `paused` | User said "not now" | Don't ask, work with what you have |
| `never_ask` | User said stop | Never ask for more context |

## Key Principles

- **No config keys visible** — use natural language, not "default_page_size: 100"
- **Learn from behavior** — if they always query the same database, remember it
- **Track databases loosely** — note what they use but don't maintain full inventory
- Update `last` on each use


path: pages.md
content: # Pages - Notion API

## Retrieve Page

```bash
curl 'https://api.notion.com/v1/pages/PAGE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

## Create Page in Database

```bash
curl -X POST 'https://api.notion.com/v1/pages' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"database_id": "DATABASE_ID"},
    "properties": {
      "Name": {"title": [{"text": {"content": "New Task"}}]},
      "Status": {"select": {"name": "To Do"}}
    }
  }'
```

## Create Page under Page

```bash
curl -X POST 'https://api.notion.com/v1/pages' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"page_id": "PARENT_PAGE_ID"},
    "properties": {
      "title": {"title": [{"text": {"content": "Subpage Title"}}]}
    },
    "children": [
      {"object": "block", "type": "paragraph", "paragraph": {
        "rich_text": [{"type": "text", "text": {"content": "Page content."}}]
      }}
    ]
  }'
```

## Update Page Properties

```bash
curl -X PATCH 'https://api.notion.com/v1/pages/PAGE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
```

## Archive Page

```bash
curl -X PATCH 'https://api.notion.com/v1/pages/PAGE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"archived": true}'
```

## Set Page Icon and Cover

```bash
curl -X PATCH 'https://api.notion.com/v1/pages/PAGE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "icon": {"type": "emoji", "emoji": "🚀"},
    "cover": {"type": "external", "external": {"url": "https://example.com/image.jpg"}}
  }'
```

## Page ID from URL

URL: `https://notion.so/Page-Title-abc123def456`
Page ID: `abc123def456` (last part, remove dashes)


path: pagination.md
content: # Pagination - Notion API

## Response Structure

```json
{
  "object": "list",
  "results": [...],
  "next_cursor": "abc123",
  "has_more": true
}
```

## Using Pagination

### First Request
```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"page_size": 100}'
```

### Next Page
```bash
curl -X POST 'https://api.notion.com/v1/databases/DATABASE_ID/query' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"page_size": 100, "start_cursor": "abc123"}'
```

## Complete Fetch Pattern

### Python
```python
def fetch_all(database_id):
    url = f"https://api.notion.com/v1/databases/{database_id}/query"
    headers = {
        "Authorization": f"Bearer {NOTION_API_KEY}",
        "Notion-Version": "2022-06-28"
    }
    
    results = []
    cursor = None
    
    while True:
        body = {"page_size": 100}
        if cursor:
            body["start_cursor"] = cursor
        
        response = requests.post(url, headers=headers, json=body)
        data = response.json()
        
        results.extend(data["results"])
        
        if not data.get("has_more"):
            break
        cursor = data["next_cursor"]
    
    return results
```

### JavaScript
```javascript
async function fetchAll(databaseId) {
  const results = [];
  let cursor = undefined;

  while (true) {
    const response = await fetch(
      `https://api.notion.com/v1/databases/${databaseId}/query`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${NOTION_API_KEY}`,
          'Notion-Version': '2022-06-28',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          page_size: 100,
          ...(cursor && { start_cursor: cursor }),
        }),
      }
    );

    const data = await response.json();
    results.push(...data.results);

    if (!data.has_more) break;
    cursor = data.next_cursor;
  }

  return results;
}
```

## Paginated Endpoints

| Endpoint | Max per page |
|----------|--------------|
| Database query | 100 |
| Block children | 100 |
| Search | 100 |
| Users list | 100 |
| Comments list | 100 |

## Best Practices

1. Always check `has_more`
2. Use max page_size (100)
3. Handle rate limits with retry
4. Stream large datasets


path: properties.md
content: # Property Types - Notion API

## Title (Required)
```json
{"Name": {"title": [{"type": "text", "text": {"content": "Page title"}}]}}
```

## Rich Text
```json
{"Description": {"rich_text": [{"type": "text", "text": {"content": "Text"}}]}}
```

## Number
```json
{"Price": {"number": 99.99}}
```

## Select
```json
{"Status": {"select": {"name": "In Progress"}}}
```

## Multi-Select
```json
{"Tags": {"multi_select": [{"name": "Tag1"}, {"name": "Tag2"}]}}
```

## Status
```json
{"Status": {"status": {"name": "Done"}}}
```

## Date
```json
{"Due Date": {"date": {"start": "2025-12-31"}}}
{"Duration": {"date": {"start": "2025-01-01", "end": "2025-01-07"}}}
{"Meeting": {"date": {"start": "2025-01-15T14:00:00.000+00:00", "time_zone": "America/New_York"}}}
```

## Checkbox
```json
{"Done": {"checkbox": true}}
```

## URL
```json
{"Link": {"url": "https://example.com"}}
```

## Email
```json
{"Contact": {"email": "[REDACTED_SECRET]"}}
```

## Phone
```json
{"Phone": {"phone_number": "+1-555-123-4567"}}
```

## People
```json
{"Assignee": {"people": [{"id": "USER_ID"}]}}
```

## Files
```json
{"Attachments": {"files": [{"name": "doc.pdf", "type": "external", "external": {"url": "https://example.com/doc.pdf"}}]}}
```

## Relation
```json
{"Related": {"relation": [{"id": "PAGE_ID_1"}, {"id": "PAGE_ID_2"}]}}
```

## Rollup (Read-only)
```json
{"Total": {"rollup": {"type": "number", "number": 150, "function": "sum"}}}
```

## Formula (Read-only)
```json
{"Computed": {"formula": {"type": "string", "string": "Result"}}}
```

## Created Time (Read-only)
```json
{"Created": {"created_time": "2025-01-01T12:00:00.000Z"}}
```

## Last Edited Time (Read-only)
```json
{"Updated": {"last_edited_time": "2025-01-15T14:30:00.000Z"}}
```

## Unique ID (Read-only)
```json
{"ID": {"unique_id": {"prefix": "TASK", "number": 42}}}
```

## Clear Property
```json
{"Due Date": {"date": null}}
{"Tags": {"multi_select": []}}
```


path: search.md
content: # Search and Users - Notion API

## Search

```bash
curl -X POST 'https://api.notion.com/v1/search' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{"query": "search term"}'
```

### Filter by Type

Pages only:
```json
{"query": "meeting", "filter": {"value": "page", "property": "object"}}
```

Databases only:
```json
{"filter": {"value": "database", "property": "object"}}
```

### Sort Results
```json
{"query": "project", "sort": {"direction": "descending", "timestamp": "last_edited_time"}}
```

### List All (Empty Query)
```json
{"query": "", "page_size": 100}
```

## Users

### List All Users
```bash
curl 'https://api.notion.com/v1/users' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

### Get Current Bot
```bash
curl 'https://api.notion.com/v1/users/me' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

### Get Specific User
```bash
curl 'https://api.notion.com/v1/users/USER_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

## Comments

### List Comments
```bash
curl 'https://api.notion.com/v1/comments?block_id=PAGE_ID' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

### Create Comment
```bash
curl -X POST 'https://api.notion.com/v1/comments' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"page_id": "PAGE_ID"},
    "rich_text": [{"type": "text", "text": {"content": "Comment text"}}]
  }'
```

## Search Tips

- Search is case-insensitive
- Searches page titles and content
- Does not search property values
- Results limited to pages shared with integration


path: setup.md
content: # Setup - Notion API Integration

## First-Time Setup

### 1. Create Integration

1. Go to https://www.notion.so/my-integrations
2. Click "New integration"
3. Name it (e.g., "My Agent")
4. Select workspace
5. Copy the "Internal Integration Token"

### 2. Set Environment Variable

```bash
export NOTION_API_KEY="ntn_xxxxxxxxxxxx"
# Or for older tokens:
export NOTION_API_KEY="secret_xxxxxxxxxxxx"
```

### 3. Share Pages with Integration

Integration can only access pages explicitly shared with it:

1. Open the page/database in Notion
2. Click "..." menu (top right)
3. Click "Add connections"
4. Select your integration

### 4. Test Connection

```bash
curl 'https://api.notion.com/v1/users/me' \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2022-06-28"
```

Expected: `{"object":"user","id":"...","type":"bot"}`

## Memory Setup

Create workspace context:

```bash
mkdir -p ~/notion-api-integration
```

Then initialize memory by asking the agent about your Notion workspace.

## Integration Permissions

Configure in integration settings:

| Permission | Use Case |
|------------|----------|
| Read content | Query databases, read pages |
| Update content | Edit pages, update properties |
| Insert content | Create pages, add blocks |
| Read comments | Fetch page comments |
| Create comments | Add comments to pages |

## Troubleshooting

### 404 Not Found
- Page not shared with integration
- Page ID has dashes (remove them)
- Page was deleted

### 401 Unauthorized
- Invalid or expired token
- Wrong token format

### 400 Bad Request
- Missing Notion-Version header
- Invalid JSON in request body
- Wrong property type format


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)