A Hono-based webhook handler that receives POST requests from Notion and queries the Notion API to retrieve page properties.
-
Environment Variables: Set your Notion API key and team database ID as environment variables:
NOTION_API_KEY=your_notion_integration_token EXTRANET_TEAM_DB=your_team_database_id -
Notion Integration:
- Create a Notion integration at https://www.notion.so/my-integrations
- Copy the integration token and set it as the
NOTION_API_KEYenvironment variable - Share your database/pages with the integration
Handles incoming Notion webhooks, retrieves page properties, and updates the page icon from a related client page.
Workflow:
- Receives webhook payload and extracts page ID
- Retrieves the original page properties
- Checks for a "Clients" relation property
- Fetches the first related client page
- Copies the client page's icon to the original page
Request: Notion webhook payload (JSON) Response:
{ "success": true, "message": "Webhook processed successfully - icon updated from client page", "pageId": "original-page-id", "clientPageId": "client-page-id", "iconType": "external", "updatedPage": { /* updated page object */ } }
Handles incoming Notion webhooks, retrieves page properties, and updates the page title based on the name from a related client page.
Workflow:
- Receives webhook payload and extracts page ID
- Retrieves the original page properties
- Checks for a "Clients" relation property
- Fetches the first related client page
- Extracts the client page's title/name
- Updates the original page's title to "{client_name} team page"
Example: If the client page is named "Asdf", the original page title becomes "Asdf team page"
Request: Notion webhook payload (JSON) Response:
{ "success": true, "message": "Webhook processed successfully - title updated from client page", "pageId": "original-page-id", "clientPageId": "client-page-id", "clientName": "Asdf", "newTitle": "Asdf team page", "updatedPage": { /* updated page object */ } }
Handles incoming Notion webhooks and creates an "Inbox" child database on the specified page if one doesn't already exist.
Workflow:
- Receives webhook payload and extracts page ID
- Validates required environment variable
EXTRANET_TEAM_DB - Checks existing page children for databases with "inbox" in the title (case-insensitive)
- If found, skips creation and returns existing database info
- If not found, creates new "Inbox" database as a child of the page
- Creates a template page in the new database with the webhook page ID in the "Team page" relation
Database Schema:
- Name (title): Task names
- Status (select): "Not started", "Working...", "Done", "Approved"
- Team page (relation): Single-select relation to the database specified by
EXTRANET_TEAM_DB - Team (rollup): Displays the "Team" property of the related team page
- Approver (people): Person responsible for approving the task
- Approved date (date): Date when the task was approved
Request: Notion webhook payload (JSON) Response (when created):
{ "success": true, "message": "Inbox database created successfully with template page", "pageId": "webhook-page-id", "databaseId": "new-database-id", "templatePageId": "template-page-id", "action": "created", "database": { /* created database object */ }, "templatePage": { /* created template page object */ } }
Response (when already exists):
{ "success": true, "message": "Inbox database already exists", "pageId": "webhook-page-id", "databaseId": "existing-database-id", "action": "skipped" }
Health check endpoint that returns a simple status message.
- Configure your Notion webhook to send POST requests to:
https://your-val-url.web.val.run/tasks/favicon(for icon updates)https://your-val-url.web.val.run/tasks/name(for title updates)https://your-val-url.web.val.run/tasks/inbox(for inbox database creation)
- The handlers will:
- Log the incoming webhook payload
- Extract the page ID from the payload
- Query the Notion API to get the original page properties
- For
/tasks/favicon: Check for a "Clients" relation property, fetch the first related client page, and copy the client page's icon to the original page - For
/tasks/name: Check for a "Clients" relation property, fetch the first related client page, and update the original page's title to "{client_name} team page" - For
/tasks/inbox: Check for existing "Inbox" databases in page children, and create a new one if none exists - Log all steps and return a success response
The handler supports all Notion icon types:
- Emoji: Simple emoji characters (🏢, 📊, etc.)
- External: URLs to external images
- File: Notion-hosted files
The handler gracefully handles various scenarios:
- Missing Clients property: Logs and continues without error
- Empty Clients relation: Logs and continues without error
- Client page not found: Logs error and continues without failing
- Client page has no icon: Logs and continues without error
- Icon update fails: Logs error but returns success response
All errors are logged to the console for debugging while maintaining webhook reliability.
The handler looks for the page ID in these locations within the webhook payload:
payload.data.idpayload.id
- Returns 400 if no page ID is found in the webhook payload
- Returns 500 if there's an error querying the Notion API
- All errors are logged to the console for debugging