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:
- User adds "OKR" with definition
- Define.wtf triggers
acronym.createdevent - HTTP POST sent to your configured webhook URL
- Your system receives the event and can react (e.g., sync to wiki, notify Slack, log to analytics)
Accessing Webhooks
- From the main navigation, click Admin → Webhooks
- Or navigate directly to
/admin/webhooks
Creating Webhooks
Set up a new webhook subscription:
Step 1: Configure Webhook
- Click Create Webhook button
- 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)
- 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
- (Optional) Add Description: Why this webhook exists ("Slack notifications", "Wiki sync", etc.)
- Click Create
Step 2: Verify & Test
After creation:
- Define.wtf sends a test event to verify endpoint is reachable
- Your service should respond with HTTP 200-299 (success) within 30 seconds
- If test fails: Error message explains why (timeout, 4xx/5xx response, unreachable)
- Fix issues and click Retry Test
- 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_secretTo verify authenticity:
- Get webhook secret (shown in webhook settings)
- Extract the secret from the
X-Webhook-Secretheader - Compare to your stored secret value
- 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 TrueWebhook 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
- Click on a webhook in the list
- See:
- Endpoint URL
- Subscribed events
- Creation date
- Last delivery status
- Signing secret
- Delivery statistics
Edit Webhook
- Click Edit on webhook
- Modify:
- Events (add/remove subscriptions)
- Retry policy (if enterprise)
- Description
- Click Save
Cannot change endpoint URL directly (security); delete and recreate if needed.
Disable Webhook
Temporarily stop webhook without deleting:
- Click Disable on webhook
- No events sent while disabled
- Click Enable to reactivate
Delete Webhook
Permanently remove webhook:
- Click Delete on webhook
- Confirm deletion
- No events sent after deletion
Webhook Logs
View all webhook delivery attempts:
Access Logs
- Click a webhook → Logs tab
- 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:
- Click log entry
- Click Re-deliver
- Confirms re-delivery queued
- Check logs for new delivery attempt
Testing Webhooks
Manual Test
- Open webhook details
- Click Send Test Event
- Choose event type from dropdown
- Generates sample payload and sends
- View delivery log to see result
Use this to verify endpoint is working before relying on webhooks.
Webhook Debugging
To debug webhook issues:
- Log incoming requests: Add logging to your endpoint
- Verify signature: Check X-Define-Signature header
- Check status code: Return 2xx
- Check timeout: Respond within 30 seconds
- Monitor logs: Check Define.wtf webhook logs for delivery status
- 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.