Skip to content
Skip to main content

Sync calendar events to Notion

Last updated:

Notion is where a lot of teams plan their week, but it doesn’t pull in calendar events on its own. People copy meetings over by hand, the database drifts, and the “this week” view stops matching reality. You want each meeting to land as a row in a Notion database the moment it’s booked or changed, with a real date property you can sort and filter on.

This recipe wires the Nylas Calendar API to a Notion database. You subscribe to event webhooks, fetch the changed event, map it to Notion’s page schema, and write a database page through the Notion API. One pipeline covers Google, Outlook, and Exchange, so you don’t write provider-specific calendar code. If you’re pushing into a sales tool instead, the sync calendar events to a CRM recipe is a closer fit, and two-way calendar sync covers writing changes back to the calendar.

The pipeline is one webhook-driven flow with four steps. Each calendar change becomes exactly one Notion database page, keyed so a reschedule updates the same row instead of adding a duplicate. The loop touches two APIs and stays under the Notion limit of 3 requests per second.

  1. Subscribe to the event.created and event.updated webhook triggers on your Nylas application.
  2. Fetch the full event from the Nylas Events API when a notification arrives.
  3. Map Nylas event fields to Notion properties, converting Unix timestamps to ISO dates for a Notion date property.
  4. Write the page to your Notion database with a create or update call.

Make sure you have the following before starting this tutorial:

  • A Nylas account with an active application
  • A valid API key from your Nylas Dashboard
  • At least one connected grant (an authenticated user account) for the provider you want to work with
  • Node.js 18+ or Python 3.8+ installed (depending on which code samples you follow)

You also need:

  • A connected grant with calendar read access for at least one user
  • A Notion internal integration and its API token
  • A Notion database shared with that integration, with a title property and a date property
  • A publicly reachable HTTPS endpoint to receive webhook notifications

Create a database in Notion with at least two columns: a Title property (the default Name column works) and a Date property. The Notion API can only write to a database that’s explicitly shared with your integration, so open the database, click the menu, and add your integration as a connection. Copy the 32-character database ID from the database URL. According to the Notion API docs, property keys in your write requests must match the database’s column names exactly, so note the date column’s name now.

How do you sync calendar events to a Notion database?

Section titled “How do you sync calendar events to a Notion database?”

Subscribe to Nylas event webhooks, then write each change to Notion as a database page. When the event.created or event.updated trigger fires, Nylas sends a POST to your endpoint, you fetch the full event, and you call the Notion API to create or update a page whose date property holds the meeting time. One subscription covers every connected grant.

The mapping is the part worth getting right. A Nylas event stores its start and end as Unix timestamps inside a when object, while a Notion date property expects ISO 8601 strings. You convert once, in your handler, and store the Nylas event id somewhere on the Notion page so a later event.updated finds the same row. The two systems speak different field names, so here are the 5 fields you’ll map across both providers.

Nylas event fieldNotion property typeNotes
titletitleThe default Name column in most databases
when.start_time / when.end_timedateUnix seconds; convert to ISO start and end
descriptionrich_textOptional column for the meeting agenda
location or conferencing.details.urlurl or rich_textJoin link for video meetings
idrich_textStore it to match future updates to the same page

Create one webhook subscription that listens for both event lifecycle triggers. A single subscription covers every grant in your Nylas application, so you don’t register per-user webhooks. The POST /v3/webhooks request below registers the 2 event triggers and points them at your callback URL. Nylas sends a challenge request to confirm the endpoint before it goes live.

Save the webhook_secret from the response. You use it to verify the X-Nylas-Signature header on every incoming notification so an attacker can’t forge calendar changes into your Notion workspace. For the full subscription lifecycle and signature verification, see sync calendar events with webhooks.

A webhook notification carries the event id, grant_id, and calendar_id, but not the full event body. Fetch the complete record with GET /v3/grants/{grant_id}/events/{event_id}, which takes the grant ID and event ID positionally in the SDKs and needs the calendar_id from the webhook payload as a query parameter. The same endpoint covers all 3 providers and returns the 4 fields you’ll map into Notion: the when timestamps, title, description, and participants.

The when object reports start_time and end_time as Unix seconds (for example, 1701977400), with separate start_timezone and end_timezone strings. Convert the 2 timestamps to ISO 8601 before you hand them to Notion, because the Notion date property rejects raw epoch integers.

Create the Notion page with POST /v1/pages, the Notion create-page endpoint. Set parent.database_id to your database ID, then fill properties with a title and a date. The Notion date property takes ISO 8601 strings in start and end, which is why you converted the Unix timestamps in the previous step. Every Notion request needs the Notion-Version header; the current version is 2026-03-11 per the Notion versioning docs.

For an event.updated trigger, you patch the existing page instead of creating a second one. Query the database with POST /v1/databases/{database_id}/query, filtering the Nylas Event ID column for the event you stored, then send the new times to PATCH /v1/pages/{page_id}. This keeps one Notion row per meeting even after three or four reschedules.

A few Notion-specific limits shape this integration, and they differ from how the Nylas Calendar API behaves. The Notion API rate-limits each integration to an average of 3 requests per second and returns HTTP 429 with a Retry-After header when you exceed it, so a burst of calendar changes needs a small queue between your webhook handler and the Notion write.

  • Sharing is mandatory. The integration can only read or write a database that a workspace member has explicitly shared with it. A 404 from /v1/pages almost always means the database isn’t connected to the integration, not that the ID is wrong.
  • Property keys are case-sensitive. The keys in your properties object must match the database column names exactly, including capitalization. A typo drops that property without returning an error.
  • Date properties take ISO 8601, not epochs. Notion’s date type expects strings like 2025-11-12T09:30:00-08:00. Pass the start_timezone from the Nylas when object through to the offset so the meeting shows at the right local time.
  • Title is required. Every Notion page needs a non-empty title property. Calendar events occasionally have a blank title, so fall back to a placeholder like Untitled event before you write.
  • Versioning is pinned by header. Notion ties breaking changes to the Notion-Version date you send. Pin it explicitly rather than relying on a default, and review the Notion changelog before bumping it.

For the deletion path, Notion’s API archives pages rather than hard-deleting them. Handle a future event.deleted trigger by patching the page with "archived": true.