• Townie
    AI
  • Blog
  • Docs
  • Pricing
  • Weโ€™re hiring!
Log inSign up
wolf

wolf

extranet

Public
Like
extranet
Home
Code
3
README.md
H
index.ts
main.tsx
Branches
2
Pull requests
Remixes
History
Environment variables
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data โ€“ all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
8/21/2025
README.md

Notion Webhook Handler

A Hono-based webhook handler that receives POST requests from Notion and queries the Notion API to retrieve page properties.

Setup

  1. 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
    
  2. Notion Integration:

    • Create a Notion integration at https://www.notion.so/my-integrations
    • Copy the integration token and set it as the NOTION_API_KEY environment variable
    • Share your database/pages with the integration

Endpoints

POST /tasks/favicon

Handles incoming Notion webhooks, retrieves page properties, and updates the page icon from a related client page.

Workflow:

  1. Receives webhook payload and extracts page ID
  2. Retrieves the original page properties
  3. Checks for a "Clients" relation property
  4. Fetches the first related client page
  5. 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 */ } }

POST /tasks/name

Handles incoming Notion webhooks, retrieves page properties, and updates the page title based on the name from a related client page.

Workflow:

  1. Receives webhook payload and extracts page ID
  2. Retrieves the original page properties
  3. Checks for a "Clients" relation property
  4. Fetches the first related client page
  5. Extracts the client page's title/name
  6. 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 */ } }

POST /tasks/inbox

Handles incoming Notion webhooks and creates an "Inbox" child database on the specified page if one doesn't already exist.

Workflow:

  1. Receives webhook payload and extracts page ID
  2. Validates required environment variable EXTRANET_TEAM_DB
  3. Checks existing page children for databases with "inbox" in the title (case-insensitive)
  4. If found, skips creation and returns existing database info
  5. If not found, creates new "Inbox" database as a child of the page
  6. 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" }

GET /

Health check endpoint that returns a simple status message.

Usage

  1. 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)
  2. 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

Icon Handling

The handler supports all Notion icon types:

  • Emoji: Simple emoji characters (๐Ÿข, ๐Ÿ“Š, etc.)
  • External: URLs to external images
  • File: Notion-hosted files

Error Handling

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.

Webhook Payload Structure

The handler looks for the page ID in these locations within the webhook payload:

  • payload.data.id
  • payload.id

Error Handling

  • 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
Get started with a template:
FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
Weโ€™re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
ยฉ 2025 Val Town, Inc.