Notion API Changelog April 2026: Every Developer-Facing Change
Notion API Changelog April 2026: Every Developer-Facing Change
Notion shipped API version 2026-04-01 in the first week of April 2026. The update includes eight new Views API endpoints, expanded smart filter operators, webhook delivery improvements, and two new block types. This post covers every change, shows the request/response shapes, and flags the migration gotchas you will hit when upgrading from 2026-03-01.
What Shipped in April 2026
The April changelog is one of the larger API updates Notion has released. Most of the changes center on programmable database views, which were previously only configurable through the Notion UI.
| Change | Category | API Version | Breaking? |
|---|---|---|---|
| Views API (8 endpoints) | New feature | 2026-04-01 | No |
| Smart filter relative dates | Enhancement | 2026-04-01 | No |
| Smart filter "me" operator | Enhancement | 2026-04-01 | No |
| Webhook retry backoff update | Infrastructure | 2026-04-01 | No |
| Webhook event_type field addition | Enhancement | 2026-04-01 | No |
| Toggle heading block type | New block | 2026-04-01 | No |
| Synced block copy support | New block | 2026-04-01 | No |
| archived filter on database queries | Enhancement | 2026-04-01 | No |
| Rate limit header changes | Infrastructure | 2026-04-01 | Yes (soft) |
| Pagination cursor format change | Infrastructure | 2026-04-01 | Yes (soft) |
Tip
None of the April changes are hard breaking. You can upgrade by setting the Notion-Version header to 2026-04-01. The two "soft breaking" changes (rate limit headers and pagination cursors) only affect code that parses those values directly.
Views API: 8 New Endpoints
The biggest addition is the Views API. Before April 2026, there was no way to create, read, update, or delete database views through the API. If your integration needed a filtered or sorted view, you had to set up the view manually in the Notion UI and then query the database with equivalent filter/sort parameters.
Now you can manage views programmatically:
# List all views on a database
curl -X GET "https://api.notion.com/v1/databases/{database_id}/views" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-H "Notion-Version: 2026-04-01"
# Create a new table view with a filter
curl -X POST "https://api.notion.com/v1/databases/{database_id}/views" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-H "Notion-Version: 2026-04-01" \
-H "Content-Type: application/json" \
-d '{
"type": "table",
"name": "Active Tasks",
"filter": {
"property": "Status",
"status": { "equals": "In Progress" }
},
"sorts": [
{ "property": "Due Date", "direction": "ascending" }
]
}'
Endpoint Reference
| Method | Path | Description |
|---|---|---|
| GET | /v1/databases/{id}/views | List views on a database |
| POST | /v1/databases/{id}/views | Create a new view |
| GET | /v1/views/{id} | Retrieve a single view |
| PATCH | /v1/views/{id} | Update a view's config |
| DELETE | /v1/views/{id} | Delete a view |
| POST | /v1/views/{id}/duplicate | Clone a view |
| PATCH | /v1/views/{id}/properties | Configure visible columns |
| POST | /v1/views/{id}/query | Query a database through a specific view |
The /v1/views/{id}/query endpoint is particularly useful. Instead of rebuilding a view's filter and sort logic in your integration code, you can query through the view directly and get the same results the user sees in the Notion UI.
Supported View Types
The API supports five view types: table, board, timeline, calendar, and list. Gallery views are not yet supported through the API (the endpoint returns a 400 if you try to create one).
Smart Filter Improvements
Two new filter operators landed in 2026-04-01:
Relative Date References
You can now filter by relative dates without computing timestamps in your integration code. The new operators are past_week, past_month, next_week, next_month, and this_week.
{
"filter": {
"property": "Due Date",
"date": {
"this_week": {}
}
}
}
Before this update, you had to calculate the start and end of the current week in your timezone and pass explicit on_or_after / on_or_before values. The new operators handle timezone logic server-side using the workspace's configured timezone.
The "me" Operator
For people type properties, you can now use "me" as a filter value that resolves to the integration's connected user (or the user who authorized the OAuth token):
{
"filter": {
"property": "Assigned To",
"people": {
"contains": "me"
}
}
}
This is especially useful for building personal dashboards where each user sees only their own assignments. Previously, you needed to resolve the current user's Notion ID first and pass it explicitly.
Webhook Improvements
The webhook system (introduced in March 2026) received two upgrades:
New event_type Field
Webhook payloads now include an event_type field at the top level. Before, you had to inspect the nested data object to determine what happened. The new field simplifies routing:
{
"event_type": "page.property_changed",
"event_id": "evt_abc123",
"timestamp": "2026-04-09T14:23:01.000Z",
"data": {
"page_id": "page_xyz",
"property": "Status",
"old_value": { "status": { "name": "To Do" } },
"new_value": { "status": { "name": "Done" } }
}
}
The supported event types are:
| Event Type | Trigger |
|---|---|
| page.created | New page added to database |
| page.updated | Any page property changed |
| page.property_changed | Specific property changed |
| page.deleted | Page moved to trash |
| page.restored | Page restored from trash |
| block.created | Block added to a page |
| block.updated | Block content changed |
| block.deleted | Block removed |
Retry Backoff Changes
The retry window expanded from 24 hours to 48 hours, and the backoff schedule changed. Retries now happen at 1 minute, 5 minutes, 30 minutes, 2 hours, 8 hours, 24 hours, and 48 hours (seven attempts total, up from five). If your endpoint is down for a brief maintenance window, you are less likely to miss events.
New Block Types
Toggle Heading
The API now supports heading_1, heading_2, and heading_3 blocks with a is_toggleable property:
{
"type": "heading_2",
"heading_2": {
"rich_text": [{ "text": { "content": "FAQ Section" } }],
"is_toggleable": true,
"children": [
{
"type": "paragraph",
"paragraph": {
"rich_text": [{ "text": { "content": "Content hidden under the toggle." } }]
}
}
]
}
}
Toggle headings have been available in the Notion UI for over a year, but the API previously treated them as plain headings and silently dropped the toggle children on read. Now the is_toggleable field is returned on GET requests and accepted on POST/PATCH.
Synced Block Copy
You can now create a synced copy of an existing synced block via the API:
{
"type": "synced_block",
"synced_block": {
"synced_from": {
"block_id": "original_block_id"
}
}
}
The synced_from.block_id must reference the original (source) synced block, not another copy. Attempting to sync from a copy returns a 400 with a message pointing you to the original.
Rate Limit Header Changes
The rate limit response headers changed format in 2026-04-01:
| Old Header (pre-April) | New Header (April+) | Example |
|---|---|---|
| X-RateLimit-Limit | RateLimit-Limit | 3 |
| X-RateLimit-Remaining | RateLimit-Remaining | 2 |
| X-RateLimit-Reset | RateLimit-Reset | 1 (seconds) |
| (none) | RateLimit-Policy | 3;w=1 |
The X- prefixed headers are still returned alongside the new ones for backward compatibility, but the Notion team has marked them as deprecated. If your retry logic parses these headers directly, update to the new names. The RateLimit-Policy header follows the IETF draft standard (RFC 9110) and tells you the quota window size.
Warning
The RateLimit-Reset value changed from a Unix timestamp to a delta in seconds. If your retry logic does reset_time - current_time, it will compute a wildly wrong sleep duration with the new format. Check which API version your requests use before parsing this header.
Pagination Cursor Format Change
Pagination cursors returned by 2026-04-01 are now opaque base64-encoded strings instead of the previous UUID-like format. The cursors from the old format still work when passed to newer API versions, but cursors from the new format do not work with older API versions. If your system stores cursors across sessions (for incremental sync, for example), you will need to invalidate stored cursors when you upgrade your Notion-Version header.
Archived Pages Filter
Database queries now accept an archived filter parameter:
curl -X POST "https://api.notion.com/v1/databases/{database_id}/query" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-H "Notion-Version: 2026-04-01" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"property": "Status",
"status": { "equals": "Done" }
},
"archived": true
}'
Setting "archived": true returns only archived (trashed) pages. Setting it to false (the default) returns only active pages. This is useful for building "recently deleted" views or audit trails. Before this parameter, archived pages were invisible to the API entirely.
Migration Checklist
If you are upgrading from 2026-03-01 to 2026-04-01, here is what to check:
Notion-Version header to 2026-04-01X-RateLimit prefixed headers to RateLimit prefixed headersRateLimit-Reset parsing (now seconds delta, not Unix timestamp)event_type at top levelis_toggleable field (may affect content diffing)Common Pitfalls
-
Gallery view creation via API: The endpoint accepts a
typefield but returns400for"gallery". There is no error message explaining that gallery is unsupported; you just get a generic validation error. Check the view type before creating. -
Synced block chain: Trying to sync from a synced copy (instead of the original) silently returns a
400. If your code discovers synced blocks by traversing a page, you need to check thesynced_fromfield to find the original. -
Cursor migration: If you cache
start_cursorvalues for incremental database syncs, upgrading the API version mid-sync will break. Finish any in-progress sync before changing theNotion-Versionheader, or reset your sync state entirely. -
Relative date timezone: The new relative date filters use the workspace timezone, not UTC and not the requesting user's timezone. If your workspace is set to
America/Los_Angelesand your server is in UTC, "this_week" starts on Sunday Pacific time. Verify your workspace timezone setting matches your expectations. -
Rate limit double headers: Both old and new rate limit headers are returned simultaneously. If your HTTP client merges duplicate header names (some do), you may get unexpected values. Parse by the new header name explicitly.
Minimal Working Example
A complete script that creates a filtered view on a database, queries through it, and prints results:
import requests
import os
NOTION_TOKEN = os.environ["NOTION_TOKEN"]
DATABASE_ID = os.environ["NOTION_DATABASE_ID"]
BASE = "https://api.notion.com/v1"
HEADERS = {
"Authorization": f"Bearer {NOTION_TOKEN}",
"Notion-Version": "2026-04-01",
"Content-Type": "application/json",
}
# Create a view showing only this week's tasks
view = requests.post(
f"{BASE}/databases/{DATABASE_ID}/views",
headers=HEADERS,
json={
"type": "table",
"name": "This Week",
"filter": {
"property": "Due Date",
"date": {"this_week": {}},
},
"sorts": [{"property": "Due Date", "direction": "ascending"}],
},
).json()
print(f"Created view: {view['id']}")
# Query through the view
results = requests.post(
f"{BASE}/views/{view['id']}/query",
headers=HEADERS,
json={},
).json()
for page in results.get("results", []):
title_prop = page["properties"].get("Name", {})
title = title_prop.get("title", [{}])[0].get("plain_text", "Untitled")
print(f" - {title}")
Wrapping Up
The April 2026 Notion API update is primarily about the Views API, which fills one of the longest-standing gaps in the platform's developer tooling. The smart filter improvements and webhook upgrades are smaller but immediately practical. If you are upgrading, the rate limit header change and pagination cursor format are the two things most likely to bite you in production.
Fazm is an open source macOS AI agent. Open source on GitHub.