define.wtf
Admin Guide

Webhooks

Subscribe to workspace events and integrate with external systems

Webhooks

Webhooks enable real-time integration with external systems by firing HTTP requests when events occur in your Define.wtf workspace. This guide covers webhook setup, event types, delivery, and debugging.

What Are Webhooks?

Webhooks are automated HTTP POST requests sent from Define.wtf to your external service whenever specific events occur.

Example: When a team member creates a new acronym:

  1. User adds "OKR" with definition
  2. Define.wtf triggers acronym.created event
  3. HTTP POST sent to your configured webhook URL
  4. Your system receives the event and can react (e.g., sync to wiki, notify Slack, log to analytics)

Accessing Webhooks

  1. From the main navigation, click AdminWebhooks
  2. Or navigate directly to /admin/webhooks

Creating Webhooks

Set up a new webhook subscription:

Step 1: Configure Webhook

  1. Click Create Webhook button
  2. Enter Endpoint URL:
    • Must be HTTPS (no http:// endpoints for security)
    • Example: https://api.example.com/webhooks/define
    • Endpoint must be publicly accessible (Define.wtf servers must reach it)
  3. Select Events to subscribe to:
    • Check one or more event types (see Event Types section)
    • "All events" option subscribes to all current and future events
  4. (Optional) Add Description: Why this webhook exists ("Slack notifications", "Wiki sync", etc.)
  5. Click Create

Step 2: Verify & Test

After creation:

  1. Define.wtf sends a test event to verify endpoint is reachable
  2. Your service should respond with HTTP 200-299 (success) within 30 seconds
  3. If test fails: Error message explains why (timeout, 4xx/5xx response, unreachable)
  4. Fix issues and click Retry Test
  5. Once verified, webhook is Active

Webhook URL Requirements

Your endpoint must:

  • HTTPS: TLS 1.2+ required (no HTTP)
  • Reachable: Must be publicly accessible (IP whitelisting configurable for enterprise)
  • Response time: Reply within 30 seconds
  • Status code: Return 2xx (200-299) for success
  • Stability: Should accept POST requests even during high volume (may receive 50+ requests in burst)

Event Types

Acronym Events

acronym.created

  • Fired when: New acronym added to workspace
  • Payload: Acronym ID, term, title, description, categories, created_by
  • Use case: Sync to wiki, notify team

acronym.updated

  • Fired when: Acronym definition or metadata changed
  • Payload: Acronym ID, changed fields, before/after values
  • Use case: Track changes, update external system

acronym.locked

  • Fired when: Acronym marked as read-only
  • Payload: Acronym ID, term, lock reason
  • Use case: Notify editors of locked terms

acronym.unlocked

  • Fired when: Lock removed from acronym
  • Payload: Acronym ID, term
  • Use case: Notify editors lock lifted

acronym.deprecated

  • Fired when: Acronym marked as outdated
  • Payload: Acronym ID, term, deprecation reason, replacement_term (if provided)
  • Use case: Archive in external system, notify users

acronym.restored

  • Fired when: Deprecated acronym restored
  • Payload: Acronym ID, term
  • Use case: Update external status

acronym.deleted

  • Fired when: Acronym moved to trash (soft-delete)
  • Payload: Acronym ID, term, deleted_by, deleted_at
  • Use case: Archive in external system (not hard-delete)

acronym.permanently_deleted

  • Fired when: Acronym hard-deleted from trash (irreversible)
  • Payload: Acronym ID, term, deleted_by, deleted_at
  • Fired by: Owner only (rare)
  • Use case: Compliance, audit trail

Category Events

category.created

  • Fired when: New category added
  • Payload: Category ID, name, color, created_by
  • Use case: Sync categories to external system

category.updated

  • Fired when: Category name or color changed
  • Payload: Category ID, changed fields, before/after values
  • Use case: Update external category references

category.deleted

  • Fired when: Category removed
  • Payload: Category ID, name, deleted_by, reassigned_to (if applicable)
  • Use case: Cleanup in external system

User Events

user.created

  • Fired when: New user created (via SSO or SCIM)
  • Payload: User ID, email, name, role
  • Use case: Log to audit system, notify admins

user.deactivated

  • Fired when: User account deactivated
  • Payload: User ID, email, deactivated_at
  • Use case: Sync to external systems, revoke access

user.authenticated

  • Fired when: User logs in via SSO or email
  • Payload: User ID, email, method (sso or email)
  • Use case: Log authentication events, sync activity

Collection Events

collection.created

  • Fired when: New collection created
  • Payload: Collection ID, name, description, item_count, created_by
  • Use case: Announce new onboarding collection

collection.updated

  • Fired when: Collection items added/removed or metadata changed
  • Payload: Collection ID, changed fields
  • Use case: Keep external course catalog in sync

collection.deleted

  • Fired when: Collection deleted
  • Payload: Collection ID, name, deleted_by
  • Use case: Remove from external system

Bulk Import Event

import.completed

  • Fired when: Bulk import finishes
  • Payload: Import ID, stats (created, updated, skipped), imported_by, duration
  • Use case: Trigger downstream syncs, notify team of import

import.failed

  • Fired when: Import encounters error
  • Payload: Import ID, error message, attempted_row_count, failed_at
  • Use case: Alert admin of import issues

Webhook Payload Format

All webhooks send POST requests with JSON payload:

Request Format

POST /your-endpoint HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-Define-Signature: sha256=abcd1234...
X-Define-Webhook-ID: webhook_xyz789
X-Define-Delivery-ID: delivery_abc123
X-Define-Event: acronym.created
User-Agent: Define.wtf/1.0

{
  "event": "acronym.created",
  "timestamp": "2026-03-28T10:15:00Z",
  "webhook_id": "webhook_xyz789",
  "delivery_id": "delivery_abc123",
  "tenant_id": "tenant_123",
  "data": {
    "acronym": {
      "id": "acr_abc123",
      "term": "OKR",
      "title": "Objectives and Key Results",
      "description": "A goal-setting framework...",
      "categories": ["Management", "Goal Setting"],
      "tags": ["planning", "goals"],
      "created_by": "user_123",
      "created_at": "2026-03-28T10:15:00Z"
    }
  }
}

Secret Verification

Each webhook includes a plaintext secret in the header:

X-Webhook-Secret: your_webhook_secret

To verify authenticity:

  1. Get webhook secret (shown in webhook settings)
  2. Extract the secret from the X-Webhook-Secret header
  3. Compare to your stored secret value
  4. If mismatch: Reject request (possible forgery)

Example (Python):

def verify_webhook(request, stored_secret):
    header_secret = request.headers.get("X-Webhook-Secret", "")

    if header_secret != stored_secret:
        raise ValueError("Invalid webhook secret")

    # Secret verified; process webhook
    return True

Webhook Delivery

Delivery Guarantee

  • Fire-and-forget: Webhook is sent once asynchronously when the event occurs
  • Single attempt: No automatic retries if delivery fails
  • Timeout: 10 seconds per request
  • Logging: All delivery attempts are recorded with status codes and response bodies

Important: Your endpoint should be reliable; there are no automatic retries if the first attempt fails.

Response Handling

Define.wtf logs all responses:

  • 2xx (200-299): Logged as success
  • 3xx, 4xx, 5xx: Logged with status code
  • Timeout (>10s): Logged as failure

Manual re-delivery is available from the webhook logs if needed.

Managing Webhooks

View Webhook Details

  1. Click on a webhook in the list
  2. See:
    • Endpoint URL
    • Subscribed events
    • Creation date
    • Last delivery status
    • Signing secret
    • Delivery statistics

Edit Webhook

  1. Click Edit on webhook
  2. Modify:
    • Events (add/remove subscriptions)
    • Retry policy (if enterprise)
    • Description
  3. Click Save

Cannot change endpoint URL directly (security); delete and recreate if needed.

Disable Webhook

Temporarily stop webhook without deleting:

  1. Click Disable on webhook
  2. No events sent while disabled
  3. Click Enable to reactivate

Delete Webhook

Permanently remove webhook:

  1. Click Delete on webhook
  2. Confirm deletion
  3. No events sent after deletion

Webhook Logs

View all webhook delivery attempts:

Access Logs

  1. Click a webhook → Logs tab
  2. See table of all deliveries:
    • Event type
    • Timestamp
    • Status (Success, Failed, Pending, Retrying)
    • Response code
    • Response time
    • Response body (first 500 characters)

Filter Logs

  • Status: Success, Failed, Pending, Retrying
  • Event: Filter by event type
  • Date Range: Custom dates

View Delivery Details

Click a log entry to see:

  • Full request body (JSON payload)
  • Full response body
  • Request headers
  • Response headers
  • Signature (for verification)
  • Retry history (if applicable)

Re-deliver

Manually re-send a failed webhook:

  1. Click log entry
  2. Click Re-deliver
  3. Confirms re-delivery queued
  4. Check logs for new delivery attempt

Testing Webhooks

Manual Test

  1. Open webhook details
  2. Click Send Test Event
  3. Choose event type from dropdown
  4. Generates sample payload and sends
  5. View delivery log to see result

Use this to verify endpoint is working before relying on webhooks.

Webhook Debugging

To debug webhook issues:

  1. Log incoming requests: Add logging to your endpoint
  2. Verify signature: Check X-Define-Signature header
  3. Check status code: Return 2xx
  4. Check timeout: Respond within 30 seconds
  5. Monitor logs: Check Define.wtf webhook logs for delivery status
  6. Test locally: Use tool like ngrok to expose local endpoint for testing

Sample Endpoint (Node.js/Express)

const express = require("express");
const crypto = require("crypto");

app.post("/webhooks/define", (req, res) => {
  // 1. Verify signature
  const signature = req.headers["x-define-signature"].split("=")[1];
  const hash = crypto
    .createHmac("sha256", process.env.DEFINE_WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex");

  if (signature !== hash) {
    return res.status(401).send("Invalid signature");
  }

  // 2. Process webhook
  const event = req.body.event;
  console.log(`Received event: ${event}`, req.body.data);

  // 3. Handle different events
  if (event === "acronym.created") {
    handleAcronymCreated(req.body.data);
  }

  // 4. Respond quickly (queue processing)
  res.status(202).send("Accepted");
});

Use Cases

Slack Notifications

Notify team when key acronyms are added:

  • Event: acronym.created
  • Webhook: Posts to Slack #definitions channel
  • Payload: Acronym term, title, creator
  • Format: Slack message block with link to acronym

Wiki Sync

Keep external wiki in sync with Define.wtf:

  • Event: acronym.created, acronym.updated, acronym.deleted
  • Webhook: POST to wiki API to create/update/delete pages
  • Automation: Define.wtf becomes single source of truth

Analytics

Track all workspace changes for analytics/audit:

  • Event: All events
  • Webhook: POST to analytics database
  • Tracking: Activity, user actions, content changes
  • Reporting: Generate reports from collected data

Onboarding Automation

Trigger onboarding tasks when users join:

  • Event: user.joined
  • Webhook: Trigger HR/IT provisioning systems
  • Actions: Send welcome email, create accounts in other systems

Integration with External Systems

Sync Define.wtf with tools like:

  • Jira: Create documentation links in tickets
  • Confluence: Mirror acronyms as wiki pages
  • Slack: Notify channels of new acronyms
  • Google Workspace: Update shared docs
  • Custom systems: Any REST API

Best Practices

Webhook Design

  • Idempotent: Process same webhook twice with same result
  • Stateless: Don't assume request ordering
  • Handle duplicates: Use delivery_id to deduplicate
  • Fail gracefully: Return 2xx even if processing fails (queue for retry)

Verification & Security

  • Always verify signature: Check X-Define-Signature header
  • Use HTTPS only: Require TLS 1.2+
  • Validate content-type: Expect application/json
  • Timeout: Set timeout for webhook processing (max 30 seconds)

Reliability

  • Process asynchronously: Don't block webhook response
  • Queue events: Store events in queue for batch processing
  • Monitor delivery: Check webhook logs regularly for failures
  • Alert on errors: Set up alerts for failed deliveries

Scaling

  • Rate limiting: Define.wtf sends webhooks as they occur; don't assume rate
  • Batch processing: If overwhelmed, queue and batch process
  • Load balancing: Distribute webhook handling across multiple servers
  • Throttling: Implement on receiving end if needed

Troubleshooting

Webhook Not Firing

Check:

  • Webhook is enabled (not disabled)
  • Subscribed to the event type that occurred
  • Endpoint is publicly accessible (test from curl)
  • No firewall blocking requests
  • Webhook logs show delivery attempts

Delivery Failing (500 error)

Check:

  • Endpoint is returning 2xx status code
  • Response time is under 30 seconds
  • Endpoint is handling POST requests
  • Check endpoint logs for errors
  • Verify signature verification logic

Signature Verification Failing

Check:

  • Using correct signing secret (check webhook settings)
  • Computing HMAC-SHA256 of raw request body (not parsed JSON)
  • Comparing to header value (after "sha256=" prefix)
  • Timing attack safe comparison

Events Not Matching Payload

Check:

  • Event type matches your subscription
  • Payload schema in docs matches version of Define.wtf
  • Check webhook logs to see actual payload

Next Steps: Learn about Settings to configure other workspace-level features, or explore Bulk Import for large-scale data operations.