Notion Bulk Operations API¶
The Notion Bulk Operations API provides high-performance endpoints for bulk inserting, updating, and deleting records in Notion databases. These endpoints use the official Notion API and support concurrent operations with automatic retry logic.
Authentication¶
All bulk operation endpoints require two authentication headers:
X-API-KEY
: Your Magic Meal Kits API keyX-Notion-Token
: Your Notion integration API token (not the cookie token)
curl -X POST "https://magic-meal-kits-xxxxx.run.app/api/v1/notion/bulk-insert" \
-H "X-API-KEY: your-api-key" \
-H "X-Notion-Token: your-notion-integration-token" \
-H "Content-Type: application/json" \
-d '{
"database_id": "your-database-id",
"records": [...]
}'
Getting Your Notion Integration Token¶
- Go to Notion Integrations
- Create a new integration or use an existing one
- Copy the "Internal Integration Token" (starts with
secret_
) - Share your database with the integration by clicking "Share" on your database and adding the integration
Rate Limiting and Retry Logic¶
- Rate Limiting: All endpoints respect Notion's API rate limits
- Automatic Retry: Failed operations are automatically retried
- Concurrent Processing: Operations run concurrently for better performance
- Batch Limits: Maximum 100 records per request
Endpoints¶
Bulk Insert Records¶
Inserts multiple records into a Notion database.
POST /api/v1/notion/bulk-insert
¶
Request Headers:
X-API-KEY: your-api-key
X-Notion-Token: your-notion-integration-token
Content-Type: application/json
Request Body:
{
"database_id": "your-database-id",
"records": [
{
"Name": "John Doe",
"Email": "john@example.com",
"Status": "Active",
"Priority": "High"
},
{
"Name": "Jane Smith",
"Email": "jane@example.com",
"Status": "Inactive",
"Priority": "Medium"
}
]
}
Field | Type | Required | Description |
---|---|---|---|
database_id | String | Yes | Notion database ID |
records | Array | Yes | Array of records to insert (max 100) |
Example Request:
curl -X POST "https://magic-meal-kits-xxxxx.run.app/api/v1/notion/bulk-insert" \
-H "X-API-KEY: your-api-key" \
-H "X-Notion-Token: your-notion-integration-token" \
-H "Content-Type: application/json" \
-d '{
"database_id": "a1b2c3d4e5f6g7h8i9j0k1l2",
"records": [
{
"Name": "Project Alpha",
"Status": "In Progress",
"Priority": "High",
"Due Date": "2024-01-15"
},
{
"Name": "Project Beta",
"Status": "Planning",
"Priority": "Medium",
"Due Date": "2024-02-01"
}
]
}'
Example Response:
{
"success": true,
"total": 2,
"successful": 2,
"failed": 0,
"results": [
{
"index": 0,
"success": true,
"page_id": "page-id-1",
"data": {
"Name": "Project Alpha",
"Status": "In Progress",
"Priority": "High",
"Due Date": "2024-01-15"
}
},
{
"index": 1,
"success": true,
"page_id": "page-id-2",
"data": {
"Name": "Project Beta",
"Status": "Planning",
"Priority": "Medium",
"Due Date": "2024-02-01"
}
}
],
"failed_data": [],
"error_message": ""
}
Bulk Update Records¶
Updates multiple existing Notion pages.
POST /api/v1/notion/bulk-update
¶
Request Headers:
X-API-KEY: your-api-key
X-Notion-Token: your-notion-integration-token
Content-Type: application/json
Request Body:
{
"records": [
{
"page_id": "page-id-1",
"Status": "Completed",
"Priority": "Low"
},
{
"page_id": "page-id-2",
"Status": "In Progress",
"Notes": "Updated with new requirements"
}
]
}
Field | Type | Required | Description |
---|---|---|---|
records | Array | Yes | Array of update records (max 100) |
Example Request:
curl -X POST "https://magic-meal-kits-xxxxx.run.app/api/v1/notion/bulk-update" \
-H "X-API-KEY: your-api-key" \
-H "X-Notion-Token: your-notion-integration-token" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"page_id": "a1b2c3d4e5f6g7h8i9j0k1l2",
"Status": "Completed",
"Completion Date": "2024-01-10"
}
]
}'
Example Response:
{
"success": true,
"total": 1,
"successful": 1,
"failed": 0,
"results": [
{
"index": 0,
"success": true,
"page_id": "a1b2c3d4e5f6g7h8i9j0k1l2",
"data": {
"Status": "Completed",
"Completion Date": "2024-01-10"
}
}
],
"failed_data": [],
"error_message": ""
}
Bulk Delete Records¶
Moves multiple Notion pages to trash.
POST /api/v1/notion/bulk-delete
¶
Request Headers:
X-API-KEY: your-api-key
X-Notion-Token: your-notion-integration-token
Content-Type: application/json
Request Body:
{
"page_ids": [
"page-id-1",
"page-id-2",
"page-id-3"
]
}
Field | Type | Required | Description |
---|---|---|---|
page_ids | Array | Yes | Array of page IDs to delete (max 100) |
Example Request:
curl -X POST "https://magic-meal-kits-xxxxx.run.app/api/v1/notion/bulk-delete" \
-H "X-API-KEY: your-api-key" \
-H "X-Notion-Token: your-notion-integration-token" \
-H "Content-Type: application/json" \
-d '{
"page_ids": [
"a1b2c3d4e5f6g7h8i9j0k1l2",
"b2c3d4e5f6g7h8i9j0k1l2m3"
]
}'
Example Response:
{
"success": true,
"total": 2,
"successful": 2,
"failed": 0,
"results": [
{
"index": 0,
"success": true,
"page_id": "a1b2c3d4e5f6g7h8i9j0k1l2",
"data": {
"archived": true
}
},
{
"index": 1,
"success": true,
"page_id": "b2c3d4e5f6g7h8i9j0k1l2m3",
"data": {
"archived": true
}
}
],
"failed_page_ids": [],
"processing_time": "1.2s",
"summary": {}
}
Error Handling¶
All endpoints return standardized error responses:
{
"error": "Error message description"
}
Common HTTP status codes:
- 200 OK: All operations successful
- 207 Multi-Status: Partial success (some operations failed)
- 400 Bad Request: Invalid request parameters or data
- 401 Unauthorized: Missing or invalid API key or Notion token
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Database or page not found
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server-side error
Data Format¶
The API automatically converts simple data formats to Notion's complex property format.
Supported Property Types¶
Notion Type | Input Format | Example Input | Description |
---|---|---|---|
title | string | "Project Name" | Page title field |
rich_text | string | "Description text" | Rich text content |
number | number | 42 or 3.14 | Numeric values |
select | string | "High" | Single selection from options |
multi_select | array/string | ["Tag1", "Tag2"] or "Tag1, Tag2" | Multiple selections |
date | string | "2024-01-15" | Date in YYYY-MM-DD format |
checkbox | boolean | true/false | Checkbox state |
string | "user@example.com" | Email address | |
phone_number | string | "+1-555-123-4567" | Phone number |
url | string | "https://example.com" | Website URL |
relation | array/string | ["page-id-1", "page-id-2"] or "page-id-1,page-id-2" | Related page IDs |
status | string | "In Progress" | Status from available options |
Field Type Examples¶
Title Fields¶
{
"Name": "Project Alpha"
}
Rich Text Fields¶
{
"Description": "This is a detailed description of the project"
}
Number Fields¶
{
"Priority": 1,
"Budget": 5000.50
}
Select Fields¶
{
"Status": "In Progress",
"Priority": "High"
}
Multi-select Fields¶
{
"Tags": ["Frontend", "Backend", "Database"]
}
{
"Tags": "Frontend, Backend, Database"
}
Date Fields¶
{
"Due Date": "2024-01-15",
"Start Date": "2024-01-01"
}
Checkbox Fields¶
{
"Completed": true,
"Archived": false
}
Email Fields¶
{
"Contact Email": "user@example.com"
}
Phone Number Fields¶
{
"Phone": "+1-555-123-4567"
}
URL Fields¶
{
"Website": "https://example.com"
}
Relation Fields¶
{
"Related Projects": ["page-id-1", "page-id-2", "page-id-3"]
}
{
"Related Projects": "page-id-1,page-id-2,page-id-3"
}
Status Fields¶
{
"Project Status": "In Progress"
}
Best Practices¶
- Batch Size: Keep batch sizes reasonable (10-50 records) for optimal performance
- Error Handling: Always check the response for partial failures
- Rate Limits: The API handles rate limiting automatically, but avoid overwhelming requests
- Data Validation: Validate your data against the database schema before sending