FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight
lightweightglimpse2-runbook
Public
Like
glimpse2-runbook
Home
Code
4
_townie
13
.vtignore
deno.json
main.tsx
Branches
2
Pull requests
Remixes
3
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
/
_townie
/
07-save.md
Code
/
_townie
/
07-save.md
Search
8/14/2025
Viewing readonly version of main branch: v215
View latest version
07-save.md

Instructions for Implementing a New /tasks/url Webhook Endpoint

Context

This guide is for implementing webhook endpoints in the Glance Demo Platform Val that follow the established architectural patterns.

Pre-Implementation Analysis

  1. Understand the Architecture Patterns

    Before implementing, identify which pattern to use:
  • Data API Pattern (/api/, /views/): Controllers return data objects, routes handle HTTP
  • Webhook Handler Pattern (/tasks/*): Controllers handle HTTP requests/responses directly

For /tasks/* routes, use the Webhook Handler Pattern.

  1. Examine Existing Patterns

    Study these files to understand the established patterns:
  • /backend/controllers/glimpse.controller.ts - Example of webhook handler pattern
  • /backend/routes/tasks/_tasks.routes.ts - Existing webhook route structure
  • /backend/services/notion.service.ts - Service layer patterns
  • /backend/routes/webhookAuthCheck.ts - Authentication middleware
  1. Identify Required Components

    For a new /tasks/url endpoint, you'll need:
  • Controller function (handles HTTP directly)
  • Service function (if new Notion API calls needed)
  • Route definition
  • Documentation updates

Implementation Steps

Step 1: Extend the Service Layer (if needed)

If new external API calls are required:

  1. Location: /backend/services/notion.service.ts
  2. Pattern: Add pure API functions that return {success, data/error, timestamp} format
  3. Example: updatePageUrl(pageId, url) function
  4. Responsibilities: Only handle external API calls, no business logic

Step 2: Create the Controller

  1. Location: /backend/controllers/tasks.controller.ts
  2. Pattern: Webhook Handler Pattern - function takes Context, returns HTTP responses
  3. Function signature: export async function handleNotionWebhook(c: Context)
  4. Responsibilities:
  • Parse HTTP request (c.req.json(), c.req.header())
  • Extract and validate data from webhook payload
  • Implement business logic
  • Call service functions
  • Log success/failure with detailed context
  • Return HTTP responses with appropriate status codes (c.json(data, statusCode))

Step 3: Add the Route

  • Location: /backend/routes/tasks/_tasks.routes.ts
  • Pattern: Direct controller call
  • Implementation: app.post("/url", handleNotionWebhook)
  • Update catch-all handler: Add new endpoint to availableEndpoints array

Step 4: Update Documentation

Main README (/README.md):

  • Add endpoint to "Webhooks (Notion Integration)" section
  • Follow format: POST /tasks/url - Description (requires X-API-KEY header)

Route README (/backend/routes/tasks/README.md):

  • Add comprehensive endpoint documentation
  • Include request/response examples
  • Document error cases
  • Add testing instructions

Controller README (/backend/controllers/README.md):

  • Add controller function to examples
  • Note that it follows webhook handler pattern

Service README (/backend/services/README.md):

  • Add any new service functions to examples

Key Implementation Details

Authentication

  • All /tasks/* routes automatically use webhook authentication
  • Requires X-API-KEY header with NOTION_WEBHOOK_SECRET value
  • No additional auth setup needed in route

Webhook Payload Handling

Support multiple payload structures:

// Try multiple common webhook payload structures
if (body.data?.id) {
  pageId = body.data.id;
} else if (body.id) {
  pageId = body.id;
} else if (body.page_id) {
  pageId = body.page_id;
}

URL Construction Pattern

Use this pattern for glimpse URLs:

const host = c.req.header("host");
const glimpseUrl = `https://${host}/glimpse/${pageId}`;

Error Handling

Return structured errors with appropriate HTTP status codes:

// 400 for client errors
return c.json({ success: false, error: "Description" }, 400);

// 500 for server errors
return c.json({ success: false, error: "Description", details: result.error }, 500);

Logging Pattern

Include comprehensive logging:

console.log("Processing URL update webhook request");
console.log("Notion webhook received:", body);
console.log(`Constructed glimpse URL: ${glimpseUrl} for page ID: ${pageId}`);
console.log("Successfully updated Notion page with glimpse URL:", { pageId, url });
console.error("Failed to update Notion page:", result.error);

Success Response Format

Return detailed success responses:

return c.json({
  success: true,
  message: "Page URL updated successfully",
  pageId: pageId,
  url: glimpseUrl,
  timestamp: new Date().toISOString()
});

Testing Strategy

Authentication Testing

  1. Test without header (expect 401)
  2. Test with wrong key (expect 403)
  3. Test with correct key (expect 200 or business logic response)

Business Logic Testing

  1. Test with valid payload structure
  2. Test with missing page ID (expect 400)
  3. Test with missing host header (expect 400)
  4. Test with Notion API failures (expect 500)

Add Test Endpoint (optional)

Create a test endpoint that simulates the logic without calling external APIs:

app.post("/test-url", async (c) => {
  // Same logic but return test response instead of calling Notion API
});

Common Pitfalls to Avoid

  1. Don't mix patterns: /tasks/_ routes should use webhook handler pattern, not data API pattern
  2. Don't forget authentication: All /tasks/_ routes are automatically protected
  3. Don't skip logging: Webhook endpoints need comprehensive logging for debugging
  4. Don't forget documentation: Update all relevant README files
  5. Don't hardcode hosts: Always extract host from request headers
  6. Don't forget error cases: Handle missing data, API failures, etc.
  7. Don't skip the catch-all update: Add new endpoints to available endpoints list

Validation Checklist

Before considering implementation complete:

  • Controller follows webhook handler pattern (takes Context, returns HTTP responses)
  • Route uses direct controller call pattern
  • Service functions return consistent {success, data/error, timestamp} format
  • Comprehensive logging for success and failure cases
  • Proper HTTP status codes (400 for client errors, 500 for server errors)
  • Support for multiple webhook payload structures
  • Host extraction from request headers
  • Updated all relevant documentation
  • Added endpoint to catch-all handler's available endpoints list
  • Tested authentication (should fail with test keys)
  • Error handling for all edge cases

Final Notes

  • The webhook authentication middleware handles all security automatically
  • Focus on business logic and proper HTTP handling in the controller
  • Keep service functions pure (no business logic, just API calls)
  • Document the architectural decision when mixing patterns
  • Test thoroughly but remember authentication will block test requests without proper keys

This pattern ensures consistency with the established architecture while providing clear separation of concerns and comprehensive error handling.


Townie, stop here! Before proceeding to additional steps, confirm that this step is working correctly.

If everything is working as intended: conclude this step with these messages:

  1. Briefly summarize the work that was just completed and why it's important
  2. Provide the webhook URL
  3. Tell the user to go to the Glimpse Demos database in Notion and follow these steps:
    1. Go to the Glimpse Demos database
    2. Click the Webhook column header and then select Edit automation
    3. Under New action, select Send webhook
    4. Copy the webhook URL and paste it into the URL field
    5. Click the custom header link under the URL field
    6. For the key add X-API-KEY and for the value add the NOTION_WEBHOOK_SECRET environment variable from vars.env file
    7. Save the automation
    8. Click the Save URL button
    9. Click the URL that it generated in the URL field

Tell the user that the next few steps will add content and HTML to style the page at that URL.


Next step: add related page to the /glimpse/:id endpoint

Add related pages to the /glimpse/:id endpoint by following the instructions in /_townie/08-related.md

Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.