Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Interact with the Notion REST API to read, create, update, and delete pages, databases, and blocks.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
SKILL.md
1---2name: notion-api3description: >4This skill provides comprehensive instructions for interacting with the Notion API via REST calls.5This skill should be used whenever the user asks to interact with Notion, including reading, creating,6updating, or deleting pages, databases, blocks, comments, or any other Notion content. The skill7covers authentication, all available endpoints, pagination, error handling, and best practices.8---910# Notion API Skill1112This skill enables interaction with Notion workspaces through the Notion REST API. Use `curl` and `jq` for direct REST calls, or write ad-hoc scripts as appropriate for the task.1314## Authentication1516### API Key Handling17181. **Environment Variable**: Check if `NOTION_API_TOKEN` is available in the environment192. **User-Provided Key**: If the user provides an API key in context, use that instead203. **No Key Available**: If neither is available, use AskUserQuestion (or equivalent) to request the API key from the user2122**IMPORTANT**: Never display, log, or send `NOTION_API_TOKEN` anywhere except in the `Authorization` header. Confirm its existence, ask if missing, use it in requests—but never echo or expose it.2324### Request Headers2526All requests require these headers:2728```bash29-H "Authorization: Bearer $NOTION_API_TOKEN" \30-H "Notion-Version: 2025-09-03" \31-H "Content-Type: application/json"32```3334### Verifying Authentication3536Test the API key by retrieving the bot user:3738```bash39curl -s "https://api.notion.com/v1/users/me" \40-H "Authorization: Bearer $NOTION_API_TOKEN" \41-H "Notion-Version: 2025-09-03" | jq42```4344## Base URL and Conventions4546- **Base URL**: `https://api.notion.com`47- **API Version**: `2025-09-03` (required header)48- **Data Format**: JSON for all request/response bodies49- **IDs**: UUIDv4 format (dashes optional in requests)50- **Timestamps**: ISO 8601 format (`2020-08-12T02:12:33.231Z`)51- **Property Names**: `snake_case`52- **Empty Values**: Use `null` instead of empty strings5354## Rate Limits5556- **Average**: 3 requests per second per integration57- **Bursts**: Brief bursts above this limit are allowed58- **Rate Limited Response**: HTTP 429 with `Retry-After` header59- **Strategy**: Implement exponential backoff when receiving 429 responses6061## Request Size Limits6263| Type | Limit |64|------|-------|65| Maximum block elements per payload | 1000 |66| Maximum payload size | 500KB |67| Rich text content | 2000 characters |68| URLs | 2000 characters |69| Equations | 1000 characters |70| Email addresses | 200 characters |71| Phone numbers | 200 characters |72| Multi-select options | 100 items |73| Relations | 100 related pages |74| People mentions | 100 users |75| Block arrays per request | 100 elements |7677## Confirmation for Destructive Operations7879**IMPORTANT**: Before executing any operation that modifies or deletes data, ask the user for confirmation. This includes:80- Updating pages or blocks81- Deleting/archiving pages or blocks82- Modifying database schemas83- Creating pages (if multiple or in batch)84- Any bulk operations8586For a logical group of related operations, a single confirmation is sufficient.8788## Core API Endpoints8990### Search9192Search across all accessible pages and databases:9394```bash95curl -s -X POST "https://api.notion.com/v1/search" \96-H "Authorization: Bearer $NOTION_API_TOKEN" \97-H "Notion-Version: 2025-09-03" \98-H "Content-Type: application/json" \99-d '{100"query": "search term",101"filter": {"property": "object", "value": "page"},102"sort": {"direction": "descending", "timestamp": "last_edited_time"},103"page_size": 100104}' | jq105```106107Filter values: `"page"` or `"data_source"` (or omit for both)108109### Pages110111#### Retrieve a Page112113```bash114curl -s "https://api.notion.com/v1/pages/{page_id}" \115-H "Authorization: Bearer $NOTION_API_TOKEN" \116-H "Notion-Version: 2025-09-03" | jq117```118119**Note**: This returns page properties, not content. For content, use "Retrieve block children" with the page ID.120121#### Create a Page122123```bash124curl -s -X POST "https://api.notion.com/v1/pages" \125-H "Authorization: Bearer $NOTION_API_TOKEN" \126-H "Notion-Version: 2025-09-03" \127-H "Content-Type: application/json" \128-d '{129"parent": {"page_id": "parent-page-id"},130"properties": {131"title": {132"title": [{"text": {"content": "Page Title"}}]133}134},135"children": [136{137"object": "block",138"type": "paragraph",139"paragraph": {140"rich_text": [{"type": "text", "text": {"content": "Paragraph content"}}]141}142}143]144}' | jq145```146147Parent options:148- `{"page_id": "..."}` - Create under a page149- `{"database_id": "..."}` - Create in a database (legacy)150- `{"data_source_id": "..."}` - Create in a data source (API v2025-09-03+)151152#### Update a Page153154```bash155curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \156-H "Authorization: Bearer $NOTION_API_TOKEN" \157-H "Notion-Version: 2025-09-03" \158-H "Content-Type: application/json" \159-d '{160"properties": {161"title": {"title": [{"text": {"content": "Updated Title"}}]}162},163"icon": {"type": "emoji", "emoji": "📝"},164"archived": false165}' | jq166```167168Additional update options: `cover`, `is_locked`, `in_trash`169170#### Archive (Delete) a Page171172```bash173curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \174-H "Authorization: Bearer $NOTION_API_TOKEN" \175-H "Notion-Version: 2025-09-03" \176-H "Content-Type: application/json" \177-d '{"archived": true}' | jq178```179180#### Retrieve a Page Property Item181182For properties with more than 25 references:183184```bash185curl -s "https://api.notion.com/v1/pages/{page_id}/properties/{property_id}" \186-H "Authorization: Bearer $NOTION_API_TOKEN" \187-H "Notion-Version: 2025-09-03" | jq188```189190### Blocks (Page Content)191192#### Retrieve Block Children193194```bash195curl -s "https://api.notion.com/v1/blocks/{block_id}/children?page_size=100" \196-H "Authorization: Bearer $NOTION_API_TOKEN" \197-H "Notion-Version: 2025-09-03" | jq198```199200Use the page ID as `block_id` to get page content. Check `has_children` on each block for nested content.201202#### Append Block Children203204```bash205curl -s -X PATCH "https://api.notion.com/v1/blocks/{block_id}/children" \206-H "Authorization: Bearer $NOTION_API_TOKEN" \207-H "Notion-Version: 2025-09-03" \208-H "Content-Type: application/json" \209-d '{210"children": [211{212"object": "block",213"type": "heading_2",214"heading_2": {215"rich_text": [{"type": "text", "text": {"content": "New Section"}}]216}217},218{219"object": "block",220"type": "paragraph",221"paragraph": {222"rich_text": [{"type": "text", "text": {"content": "Content here"}}]223}224}225]226}' | jq227```228229Maximum 100 blocks per request, up to 2 levels of nesting.230231Position options in request body:232- Default: appends to end233- `"position": {"type": "start"}` - Insert at beginning234- `"position": {"type": "after_block", "after_block": {"id": "block-id"}}` - Insert after specific block235236#### Retrieve a Block237238```bash239curl -s "https://api.notion.com/v1/blocks/{block_id}" \240-H "Authorization: Bearer $NOTION_API_TOKEN" \241-H "Notion-Version: 2025-09-03" | jq242```243244#### Update a Block245246```bash247curl -s -X PATCH "https://api.notion.com/v1/blocks/{block_id}" \248-H "Authorization: Bearer $NOTION_API_TOKEN" \249-H "Notion-Version: 2025-09-03" \250-H "Content-Type: application/json" \251-d '{252"paragraph": {253"rich_text": [{"type": "text", "text": {"content": "Updated content"}}]254}255}' | jq256```257258The update replaces the entire value for the specified field.259260#### Delete a Block261262```bash263curl -s -X DELETE "https://api.notion.com/v1/blocks/{block_id}" \264-H "Authorization: Bearer $NOTION_API_TOKEN" \265-H "Notion-Version: 2025-09-03" | jq266```267268Moves block to trash (can be restored).269270### Databases271272#### Retrieve a Database273274```bash275curl -s "https://api.notion.com/v1/databases/{database_id}" \276-H "Authorization: Bearer $NOTION_API_TOKEN" \277-H "Notion-Version: 2025-09-03" | jq278```279280Returns database structure including data sources and properties.281282#### Query a Database283284```bash285curl -s -X POST "https://api.notion.com/v1/databases/{database_id}/query" \286-H "Authorization: Bearer $NOTION_API_TOKEN" \287-H "Notion-Version: 2025-09-03" \288-H "Content-Type: application/json" \289-d '{290"filter": {291"property": "Status",292"select": {"equals": "Done"}293},294"sorts": [295{"property": "Created", "direction": "descending"}296],297"page_size": 100298}' | jq299```300301See `references/filters-and-sorts.md` for comprehensive filter and sort documentation.302303#### Create a Database304305```bash306curl -s -X POST "https://api.notion.com/v1/databases" \307-H "Authorization: Bearer $NOTION_API_TOKEN" \308-H "Notion-Version: 2025-09-03" \309-H "Content-Type: application/json" \310-d '{311"parent": {"page_id": "parent-page-id"},312"title": [{"type": "text", "text": {"content": "My Database"}}],313"is_inline": true,314"initial_data_source": {315"properties": {316"Name": {"title": {}},317"Status": {318"select": {319"options": [320{"name": "To Do", "color": "red"},321{"name": "In Progress", "color": "yellow"},322{"name": "Done", "color": "green"}323]324}325},326"Due Date": {"date": {}}327}328}329}' | jq330```331332#### Update a Database333334```bash335curl -s -X PATCH "https://api.notion.com/v1/databases/{database_id}" \336-H "Authorization: Bearer $NOTION_API_TOKEN" \337-H "Notion-Version: 2025-09-03" \338-H "Content-Type: application/json" \339-d '{340"title": [{"text": {"content": "Updated Title"}}],341"description": [{"text": {"content": "Database description"}}]342}' | jq343```344345### Data Sources (API v2025-09-03+)346347Data sources are individual tables within a database. As of API version 2025-09-03, databases can contain multiple data sources.348349#### Create a Data Source350351```bash352curl -s -X POST "https://api.notion.com/v1/data_sources" \353-H "Authorization: Bearer $NOTION_API_TOKEN" \354-H "Notion-Version: 2025-09-03" \355-H "Content-Type: application/json" \356-d '{357"parent": {"type": "database_id", "database_id": "database-id"},358"title": [{"type": "text", "text": {"content": "New Data Source"}}],359"properties": {360"Name": {"title": {}},361"Description": {"rich_text": {}}362}363}' | jq364```365366### Users367368#### List All Users369370```bash371curl -s "https://api.notion.com/v1/users?page_size=100" \372-H "Authorization: Bearer $NOTION_API_TOKEN" \373-H "Notion-Version: 2025-09-03" | jq374```375376#### Retrieve a User377378```bash379curl -s "https://api.notion.com/v1/users/{user_id}" \380-H "Authorization: Bearer $NOTION_API_TOKEN" \381-H "Notion-Version: 2025-09-03" | jq382```383384#### Retrieve Bot User (Self)385386```bash387curl -s "https://api.notion.com/v1/users/me" \388-H "Authorization: Bearer $NOTION_API_TOKEN" \389-H "Notion-Version: 2025-09-03" | jq390```391392### Comments393394#### Retrieve Comments395396```bash397curl -s "https://api.notion.com/v1/comments?block_id={block_id}&page_size=100" \398-H "Authorization: Bearer $NOTION_API_TOKEN" \399-H "Notion-Version: 2025-09-03" | jq400```401402Use a page ID as `block_id` for page-level comments.403404#### Create a Comment405406On a page:407408```bash409curl -s -X POST "https://api.notion.com/v1/comments" \410-H "Authorization: Bearer $NOTION_API_TOKEN" \411-H "Notion-Version: 2025-09-03" \412-H "Content-Type: application/json" \413-d '{414"parent": {"page_id": "page-id"},415"rich_text": [{"type": "text", "text": {"content": "Comment content"}}]416}' | jq417```418419Reply to a discussion:420421```bash422curl -s -X POST "https://api.notion.com/v1/comments" \423-H "Authorization: Bearer $NOTION_API_TOKEN" \424-H "Notion-Version: 2025-09-03" \425-H "Content-Type: application/json" \426-d '{427"discussion_id": "discussion-id",428"rich_text": [{"type": "text", "text": {"content": "Reply content"}}]429}' | jq430```431432**Note**: The API cannot start new inline discussion threads or edit/delete existing comments.433434## Pagination435436Paginated endpoints return:437- `has_more`: Boolean indicating more results exist438- `next_cursor`: Cursor for the next page439- `results`: Array of items440441To iterate through all results:4424431. Make the initial request (omit `start_cursor`)4442. Check `has_more` in the response4453. If `true`, extract `next_cursor` and include it as `start_cursor` in the next request4464. Repeat until `has_more` is `false`447448Example request with cursor:449450```json451{452"page_size": 100,453"start_cursor": "v1%7C..."454}455```456457## Error Handling458459| HTTP Status | Code | Description |460|-------------|------|-------------|461| 400 | `invalid_json` | Request body is not valid JSON |462| 400 | `invalid_request_url` | URL is malformed |463| 400 | `invalid_request` | Request is not supported |464| 400 | `validation_error` | Request body doesn't match expected schema |465| 400 | `missing_version` | Missing Notion-Version header |466| 401 | `unauthorized` | Invalid bearer token |467| 403 | `restricted_resource` | Token lacks permission |468| 404 | `object_not_found` | Resource doesn't exist or not shared with integration |469| 409 | `conflict_error` | Data collision during transaction |470| 429 | `rate_limited` | Rate limit exceeded (check Retry-After header) |471| 500 | `internal_server_error` | Unexpected server error |472| 503 | `service_unavailable` | Notion unavailable or 60s timeout exceeded |473| 503 | `database_connection_unavailable` | Database unresponsive |474| 504 | `gateway_timeout` | Request timeout |475476## Best Practices4774781. **Store IDs**: When creating pages/databases, store the returned IDs for future updates4792. **Use Property IDs**: Reference properties by ID rather than name for stability4803. **Batch Operations**: Aggregate multiple small operations into fewer requests4814. **Respect Rate Limits**: Implement exponential backoff for 429 responses4825. **Check `has_more`**: Always handle pagination for list endpoints4836. **Validate Before Updates**: Retrieve current state before making updates4847. **Use Environment Variables**: Never hardcode API keys4858. **Handle Errors Gracefully**: Check response status codes and error messages4869. **Schema Size**: Keep database schemas under 50KB for optimal performance48710. **Properties Limit**: Properties with >25 page references require separate retrieval488489## References490491For detailed documentation on specific topics, see:492- `references/block-types.md` - All supported block types and their structures493- `references/property-types.md` - Database property types and value formats494- `references/filters-and-sorts.md` - Database query filter and sort syntax495- `references/rich-text.md` - Rich text object structure and annotations496