Blog
Real-Time Webhooks Guide

Real-Time Webhooks Guide

Webhooks are one of the most powerful features in the Foru.ms API. They allow your application to receive real-time notifications when events occur in your forum, enabling you to build sophisticated automations, analytics, and integrations.

What Are Webhooks?

A webhook is an HTTP callback that sends data to a URL you specify when certain events occur. Instead of constantly polling the API to check for changes, webhooks push updates to you instantly.

Think of webhooks as a "reverse API" - instead of you requesting data from Foru.ms, we send data to you when something happens.

Available Events

Foru.ms supports webhooks for the following events:

Thread Events

  • thread.created - A new thread is created
  • thread.updated - A thread is edited or its status changes
  • thread.deleted - A thread is deleted

Post Events

  • post.created - A new post (reply) is created
  • post.updated - A post is edited
  • post.deleted - A post is deleted

User Events

  • user.registered - A new user registers
  • user.updated - A user profile is updated

Setting Up Webhooks

1. Create a Webhook Endpoint

First, create an endpoint in your application that can receive POST requests:

// Express.js example
const express = require('express');
const crypto = require('crypto');
 
const app = express();
app.use(express.json());
 
app.post('/webhooks/forum', (req, res) => {
  const { event, data, timestamp, signature } = req.body;
  
  // Verify the signature (see security section)
  if (!verifySignature(req.body, signature)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Handle the event
  console.log(`Received ${event} event:`, data);
  
  // Process based on event type
  switch(event) {
    case 'thread.created':
      handleNewThread(data);
      break;
    case 'post.created':
      handleNewPost(data);
      break;
    // ... other events
  }
  
  // Always respond with 200 OK
  res.sendStatus(200);
});
 
app.listen(3000);

2. Register the Webhook via API

Use the Foru.ms API to register your webhook:

curl -X POST https://foru.ms/api/v1/webhooks \
  -H "x-api-key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/forum",
    "events": ["thread.created", "post.created"],
    "secret": "your_webhook_secret"
  }'

Response:

{
  "id": "webhook_abc123",
  "url": "https://your-server.com/webhooks/forum",
  "events": ["thread.created", "post.created"],
  "active": true,
  "secret": "your_webhook_secret",
  "createdAt": "2024-12-14T00:00:00Z"
}

Webhook Payload Structure

Every webhook request includes the following fields:

{
  "event": "thread.created",
  "timestamp": "2024-12-14T12:00:00Z",
  "data": {
    "id": "thread_123",
    "title": "New Discussion Topic",
    "body": "Thread content here...",
    "user": {
      "id": "user_456",
      "username": "john_doe",
      "displayName": "John Doe"
    },
    "tags": [
      {"id": "tag_1", "name": "General"}
    ],
    "createdAt": "2024-12-14T12:00:00Z"
  },
  "signature": "sha256=abc123..."
}

The data field contains the full object that triggered the event (thread, post, or user).

Security: Signature Verification

Always verify webhook signatures to ensure requests are genuinely from Foru.ms.

How It Works

  1. Foru.ms generates an HMAC signature using your webhook secret
  2. The signature is sent in the signature field
  3. You verify the signature by computing it yourself and comparing

Verification Code

function verifySignature(payload, receivedSignature) {
  const secret = process.env.WEBHOOK_SECRET;
  
  // Create HMAC using the payload data
  const payloadString = JSON.stringify({
    event: payload.event,
    timestamp: payload.timestamp,
    data: payload.data
  });
  
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payloadString)
    .digest('hex');
  
  // Compare signatures (use timing-safe comparison)
  return crypto.timingSafeEqual(
    Buffer.from(receivedSignature.replace('sha256=', '')),
    Buffer.from(expectedSignature)
  );
}

Important: Never skip signature verification in production. Without it, anyone could send fake webhook requests to your endpoint.

Use Cases

1. AI-Powered Content Moderation

Automatically analyze new posts with your own AI model:

async function handleNewPost(data) {
  // Send post content to your AI moderation service
  const analysis = await moderationAPI.analyze(data.body);
  
  if (analysis.flagged) {
    // Automatically flag or delete the post
    await forumAPI.deletePost(data.id);
    
    // Notify moderators
    await slack.send(`⚠️ Post flagged and removed: ${data.body.substring(0, 100)}`);
  }
}

2. Custom Analytics

Track engagement metrics in your data warehouse:

async function handleNewThread(data) {
  await analytics.track({
    event: 'thread_created',
    userId: data.user.id,
    properties: {
      threadId: data.id,
      title: data.title,
      tags: data.tags.map(t => t.name),
      timestamp: data.createdAt
    }
  });
}

3. Cross-Platform Notifications

Share new threads to social media automatically:

async function handleNewThread(data) {
  // Only share threads with specific tags
  if (data.tags.some(tag => tag.name === 'Announcement')) {
    await twitter.tweet(
      `📢 New announcement: ${data.title}\n\nRead more: https://forum.example.com/thread/${data.slug}`
    );
  }
}

4. User Onboarding

Welcome new users with automated messages:

async function handleUserRegistered(data) {
  // Send welcome email
  await email.send({
    to: data.email,
    subject: 'Welcome to our community!',
    template: 'welcome',
    data: { username: data.username }
  });
  
  // Create a welcome thread
  await forumAPI.createThread({
    title: `Welcome ${data.displayName}!`,
    body: `Please introduce yourself to the community.`,
    tagIds: ['welcome']
  });
}

Best Practices

1. Respond Quickly

Always respond with 200 OK as quickly as possible. If you need to do heavy processing, queue the work:

app.post('/webhooks/forum', async (req, res) => {
  // Verify signature
  if (!verifySignature(req.body, req.body.signature)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Queue the work
  await queue.add('process-webhook', req.body);
  
  // Respond immediately
  res.sendStatus(200);
});

2. Handle Retries

If your endpoint is down, Foru.ms will retry the webhook with exponential backoff. Make your handlers idempotent:

async function handleNewThread(data) {
  // Check if we've already processed this thread
  const exists = await db.threads.findOne({ id: data.id });
  if (exists) {
    console.log('Thread already processed, skipping');
    return;
  }
  
  // Process the thread
  await processThread(data);
  
  // Mark as processed
  await db.threads.insert({ id: data.id, processedAt: new Date() });
}

3. Monitor Your Webhooks

Log webhook events and monitor for failures:

app.post('/webhooks/forum', async (req, res) => {
  try {
    await processWebhook(req.body);
    
    // Log success
    logger.info('Webhook processed', {
      event: req.body.event,
      id: req.body.data.id
    });
    
    res.sendStatus(200);
  } catch (error) {
    // Log error
    logger.error('Webhook failed', {
      event: req.body.event,
      error: error.message
    });
    
    // Still respond with 200 to prevent retries for permanent failures
    res.sendStatus(200);
  }
});

4. Filter Events

Only subscribe to events you actually need. This reduces noise and improves performance.

Testing Webhooks

Local Development

Use a tool like ngrok (opens in a new tab) to expose your local server:

# Start ngrok
ngrok http 3000
 
# Use the ngrok URL when registering your webhook
# https://abc123.ngrok.io/webhooks/forum

Test Events

Send a test event to verify your webhook is working:

curl -X POST https://foru.ms/api/v1/integrations/test \
  -H "x-api-key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "integrationId": "webhook_abc123"
  }'

Managing Webhooks

List All Webhooks

curl https://foru.ms/api/v1/webhooks \
  -H "x-api-key: your_api_key"

Delete a Webhook

curl -X DELETE https://foru.ms/api/v1/webhooks/webhook_abc123 \
  -H "x-api-key: your_api_key"

Troubleshooting

Webhook Not Firing

  1. Check that your endpoint is publicly accessible
  2. Verify you're subscribed to the correct events
  3. Check that the webhook is marked as active
  4. Review your server logs for errors

Signature Verification Failing

  1. Ensure you're using the correct secret
  2. Verify you're computing the HMAC over the exact payload structure
  3. Check that you're comparing the signatures correctly

Timeouts

If your endpoint takes too long to respond:

  1. Move heavy processing to a background queue
  2. Respond with 200 OK immediately
  3. Process the webhook asynchronously

Next Steps

Webhooks unlock endless possibilities for automation and integration. Start building today!