Notion Webhook Integration
Use Notion webhooks to trigger Kestra flows when pages or databases are updated in your Notion workspace.
This guide shows you how to create a workflow that responds to Notion database changes, retrieves page details, and sends notifications to Slack when new tasks are assigned.
Prerequisites
Before you begin, you need:
- A Notion workspace with a database
- A Notion integration with access to your database
- A Slack workspace with webhook capabilities (Slack Webhook Documentation)
- Access to your Notion API token and Slack webhook URL
Create a Notion integration
- Go to Notion's My Integrations page
- Click "New integration"
- Give your integration a name and select your workspace
- Copy the Internal Integration Token - you'll need this for the
NOTION_API_KEY
secret
Share your database with the integration
- Open your Notion database
- Click the "..." menu in the top right
- Select "Add connections"
- Find and select your integration
- Click "Confirm" to grant access
Set up secrets in Kestra
Store your sensitive credentials as secrets or key-value pairs:
- Navigate to your namespace in the Kestra UI
- Go to the Secrets tab (Alternatively go to the KV Store tab and do the same)
- Create these secrets:
NOTION_API_KEY
: Your Notion integration tokenSLACK_WEBHOOK_URL
: Your Slack incoming webhook URL
Create the webhook flow
Create a flow that listens for Notion webhook events and processes them:
id: notion-webhook
namespace: company.team
tasks:
- id: get_notion_page_details
type: io.kestra.plugin.notion.page.Read
apiToken: "{{ secret('NOTION_API_KEY') }}"
pageId: "{{ trigger.body.entity.id }}"
- id: send_slack_alert
type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
messageText: "New task titled {{ outputs.get_notion_page_details | jq('.properties.Button.title[0].text.content') | first }} assigned to {{ outputs.get_notion_page_details | jq('.properties.Assignee.multi_select[0].name') | first }} on the Product team Notion board! Link: {{ outputs.get_notion_page_details.url }}"
triggers:
- id: notion_new_task_webhook
type: io.kestra.plugin.core.trigger.Webhook
key: my-notion-product-alert-key # Replace with a secure key
Replace my-notion-product-alert-key
with a secure, randomly generated key. Consider storing this as a secret or key-value pair for better security.
Configure Notion webhooks
Set up webhooks directly in your Notion integration:
- Go to your Notion integration settings
- Select your integration
- Navigate to the "Webhooks" section
- Click "Add webhook"
- Enter your Kestra webhook URL (see format below)
- Select the events you want to listen for:
page.property_values.updated
- When page properties changepage.created
- When new pages are createddatabase.created
- When new databases are created
- Click "Create" to save the webhook
For more details, see the Notion Webhooks API documentation.
Webhook URL format
Your Kestra webhook URL follows this pattern:
http://your-kestra-host:8080/api/v1/main/executions/webhook/{namespace}/{flow_id}/{key}
For this example:
- Namespace:
company.team
- Flow ID:
notion-webhook
- Key:
my-notion-product-alert-key
Complete URL:
http://your-kestra-host:8080/api/v1/main/executions/webhook/company.team/notion-webhook/my-notion-product-alert-key
You can copy your webhook URL directly from the Kestra UI from the Triggers tab and paste it in Notion:
Testing the integration
Test your webhook flow manually:
curl -X POST \
http://your-kestra-host:8080/api/v1/main/executions/webhook/company.team/notion-webhook/my-notion-product-alert-key \
-H "Content-Type: application/json" \
-d '{"entity": {"id": "your-notion-page-id"}}'
Replace your-notion-page-id
with an actual page ID from your Notion database.
Understanding the flow
The flow performs these steps:
- Webhook trigger: Listens for incoming webhook requests from Notion on the specified endpoint
- Get page details: Uses the Notion plugin to fetch complete page information from Notion
- Send notification: Extracts the task title and assignee information, then sends a formatted message to Slack
Customizing the flow
Different Notion properties
Modify the Slack message to use different Notion properties. Common property types include:
# For title properties
title: "{{ outputs.get_notion_page_details | jq('.properties.Title.title[0].text.content') | first }}"
# For select properties
status: "{{ outputs.get_notion_page_details | jq('.properties.Status.select.name') | first }}"
# For date properties
due_date: "{{ outputs.get_notion_page_details | jq('.properties.DueDate.date.start') | first }}"
# For people properties
assignee: "{{ outputs.get_notion_page_details | jq('.properties.Assignee.people[0].name') | first }}"
Adding conditional logic
Add conditions to process only specific types of changes:
tasks:
- id: check_status
type: io.kestra.plugin.core.flow.If
condition: "{{ outputs.get_notion_page_details | jq('.properties.Status.select.name') | first == 'In Progress' }}"
then:
- id: send_slack_alert
type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
messageText: "Task moved to In Progress: {{ outputs.get_notion_page_details | jq('.properties.Title.title[0].text.content') | first }}"
Multiple notification channels
Send notifications to different channels based on the assignee or project:
tasks:
- id: send_to_team_channel
type: io.kestra.plugin.core.flow.If
condition: "{{ outputs.get_notion_page_details | jq('.properties.Project.select.name') | first == 'Product' }}"
then:
- id: product_team_notification
type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook
url: "{{ secret('PRODUCT_SLACK_WEBHOOK_URL') }}"
messageText: "New product task assigned!"
else:
- id: general_notification
type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook
url: "{{ secret('GENERAL_SLACK_WEBHOOK_URL') }}"
messageText: "New task assigned!"
Keep in mind that the above examples are additional tasks to add to the flow and not standalone flows. You need to add id
and namespace
properties to execute them standalone.
Security considerations
- Use strong, randomly generated webhook keys
- Store all sensitive tokens as secrets or key-value pairs
- Consider implementing request validation in your webhook handler
- Regularly rotate your API tokens and webhook URLs
Related resources
Was this page helpful?