Complete guide for working with Notion API in Node.js/JavaScript projects. Use when creating, updating, fetching, or managing Notion pages, databases, and properties. Includes proper handling of rich text, database schemas, multi-select fields, dates, and complex content structures. Triggers on tasks like "create a Notion page," "update database properties," "add content to Notion," or "manage Notion workflows."
Installs into .claude/skills of the current project.
Are you the author of Notion Management?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/diegosouzapw-notion-management)
---
name: notion-management
description: Complete guide for working with Notion API in Node.js/JavaScript projects. Use when creating, updating, fetching, or managing Notion pages, databases, and properties. Includes proper handling of rich text, database schemas, multi-select fields, dates, and complex content structures. Triggers on tasks like "create a Notion page," "update database properties," "add content to Notion," or "manage Notion workflows."
license: MIT
---
# Notion Management Skill
Master working with the Notion API for Node.js/JavaScript development. This skill provides patterns, tools, and references for all common Notion operations.
## Quick Start
### Fetching Notion Resources
```typescript
// Fetch a page or database
const page = await notion_notion-fetch({
id: "page-id-or-url"
});
// Pages return markdown content and properties
// Databases return schema, data sources, and views
```
### Creating Pages
```typescript
// Single page creation
const pages = await notion_notion-create-pages({
pages: [{
properties: {
title: "My Page Title",
// Other properties based on database schema
},
content: "# Markdown content here\n\nSupports rich markdown."
}],
parent: {
data_source_id: "collection-id" // or page_id, or database_id
}
});
```
### Updating Pages
```typescript
// Update properties
await notion_notion-update-page({
page_id: "page-id",
command: "update_properties",
properties: {
title: "Updated Title",
status: "Done"
}
});
// Replace all content
await notion_notion-update-page({
page_id: "page-id",
command: "replace_content",
new_str: "# New content here"
});
// Replace specific section
await notion_notion-update-page({
page_id: "page-id",
command: "replace_content_range",
selection_with_ellipsis: "# Old heading...last paragraph.",
new_str: "# New heading\nNew content"
});
// Insert content after a section
await notion_notion-update-page({
page_id: "page-id",
command: "insert_content_after",
selection_with_ellipsis: "## Section...end of section.",
new_str: "\n## New Section\nNew content here"
});
```
## Common Property Types and Formats
### Simple Properties
- **title** (string): Page title, shown as large heading
- **rich_text** (string): Text field
- **url** (string): URL field
- **email** (string): Email field
- **phone_number** (string): Phone number
- **checkbox** (string): Use `"__YES__"` or `"__NO__"`
- **number** (number): Use JavaScript numbers, not strings
### Select Properties
```typescript
// single_select: Just use the option name
properties: {
Status: "In Progress" // Must match exact option name
}
// multi_select: Single string or comma-separated
// ❌ WRONG: ["option1", "option2"] // Don't use arrays
// ❌ WRONG: "option1,option2" // Don't use commas
// ✅ CORRECT: Need to use separate API calls or specific format
```
### Date Properties
```typescript
// Date properties use expanded format with three keys
properties: {
"date:Due Date:start": "2025-01-30",
"date:Due Date:end": null, // Optional end date
"date:Due Date:is_datetime": 0 // 0 for date, 1 for datetime
}
```
### Place Properties
```typescript
// Place/location properties use expanded format
properties: {
"place:Office:name": "HQ",
"place:Office:address": "123 Main St",
"place:Office:latitude": 37.7749,
"place:Office:longitude": -122.4194,
"place:Office:google_place_id": "optional-id"
}
```
### Special Property Names
Properties named "id" or "url" (case-insensitive) must be prefixed with "userDefined:":
```typescript
properties: {
"userDefined:id": "value",
"userDefined:URL": "https://example.com"
}
```
## Multi-Select Fields - CRITICAL
**Common mistake**: Multi-select fields have strict validation. When creating or updating pages in a database with multi_select properties:
1. **Fetch the database first** to see available options:
```typescript
const db = await notion_notion-fetch({ id: "database-id" });
// Response shows: "Tags": {"options": [{"name": "Option1"}, {"name": "Option2"}]}
```
2. **Use only valid option names**:
```typescript
properties: {
Tags: "Option1" // Single option as string
}
```
3. **For multiple options**: Currently the API has limitations. Best practice:
- Create the page with one tag
- Update it with additional tags if needed
- Or pass multiple tags separated by specific format (check database schema)
4. **Error handling**: If you get "Invalid multi_select value", check:
- Is the option name spelled exactly as shown in database?
- Are you passing a string, not an array?
- Does the database schema allow this option?
## Database Operations
### Fetch Database Schema
```typescript
const db = await notion_notion-fetch({
id: "database-id-or-url"
});
// Returns:
// - Database title and icon
// - Data sources (collections) within the database
// - Schema for each data source
// - Views available
```
### Creating Databases
```typescript
const db = await notion_notion-create-database({
title: [{type: "text", text: {content: "My Database"}}],
parent: {page_id: "parent-page-id"},
properties: {
"Task Name": {type: "title"},
"Status": {
type: "select",
select: {
options: [
{name: "To Do", color: "red"},
{name: "In Progress", color: "yellow"},
{name: "Done", color: "green"}
]
}
},
"Due Date": {type: "date"}
}
});
```
### Updating Database Schema
```typescript
await notion_notion-update-database({
database_id: "db-id",
title: [{type: "text", text: {content: "New Title"}}],
properties: {
"New Property": {type: "rich_text"},
"Property to Rename": {name: "Renamed Property"},
"Property to Delete": null // Set to null to remove
}
});
```
## Content (Markdown) Guidelines
### Supported Markdown
- **Headings**: `# H1`, `## H2`, etc.
- **Lists**: Unordered `- item`, ordered `1. item`
- **Code**: Inline `` `code` `` and code blocks
- **Bold/Italic**: `**bold**`, `*italic*`
- **Links**: `[text](url)`
- **Tables**: Full markdown table support
- **Quotes**: `> quoted text`
- **Toggles/Collapsible**: `▶ Collapsed content\n\tHidden items` (Note: indentation with tabs)
### Toggle/Collapsible Sections
Toggles are created with the `▶` character followed by content that should be hidden:
```markdown
▶ Click to expand
Hidden content line 1
Hidden content line 2
- Nested list item
```
**Important**: Content after `▶` must be indented with tabs or spaces.
### Rich Text Annotations
Content can include color and style annotations:
```markdown
# Heading {color="blue"}
Some text {color="red"} and {bold="true"}
```
## Search and Navigation
### Search Notion
```typescript
const results = await notion_notion-search({
query: "search term",
query_type: "internal" // or "user" for user search
});
// Filter by creation date
const filtered = await notion_notion-search({
query: "recent docs",
filters: {
created_date_range: {
start_date: "2025-01-01",
end_date: "2025-01-31"
}
}
});
```
### Fetch Teams and Users
```typescript
// List teams
const teams = await notion_notion-get-teams({
query: "engineering" // optional search
});
// List users
const users = await notion_notion-get-users({
query: "john", // optional search
page_size: 100
});
// Get specific user
const user = await notion_notion-get-users({
user_id: "user-id-or-self"
});
```
## Error Handling
### Common Errors and Solutions
#### "Invalid multi_select value"
**Cause**: Option name doesn't exist or format is wrong
**Solution**:
1. Fetch database to see valid options
2. Use exact option names
3. Pass as string, not array
#### "Invalid input" / Validation error
**Cause**: Wrong property format or type
**Solution**:
1. Check property type in database schema
2. Use correct format (e.g., date properties need date:Property:start format)
3. Verify special names use userDefined: prefix
#### "Page not found"
**Cause**: Wrong ID or insufficient permissions
**Solution**:
1. Verify page/database ID is correct
2. Check you have access to the resource
3. Use full URL if ID doesn't work
#### "Unauthorized"
**Cause**: Notion integration doesn't have permission
**Solution**:
1. Verify integration is shared with the database/page
2. Check integration scopes in Notion settings
3. Re-authenticate if needed
## Best Practices
1. **Always fetch first**: Before creating content in a database, fetch the database to understand its schema
2. **Validate option names**: Multi-select options are strictly validated—check exact spellings
3. **Use data_source_id for databases**: When a database has multiple data sources, use `data_source_id` instead of `database_id` as parent
4. **Handle IDs flexibly**: Most tools accept page IDs with or without dashes
5. **Content indentation**: Toggle/collapsible content must use tabs or spaces for indentation
6. **Break up complex updates**: Large content updates are safer when split into smaller operations
7. **Test with simple cases first**: Before complex automation, test with a single page/field
8. **Document environment**: Store Notion integration tokens securely, never in git
## Advanced Patterns
See [references/advanced-patterns.md](references/advanced-patterns.md) for:
- Batch operations and performance optimization
- Syncing external data to Notion
- Creating dynamic databases and views
- Handling relationships and rollups
- Complex filtering and sorting