Webhook Integration

Connect BuzzRank to any CMS or backend using our webhook API.

Overview

BuzzRank can publish content to any platform via webhooks. When an article is ready to publish, BuzzRank sends a POST request to your configured endpoint with all the article data.

Use Case: Custom CMS, headless CMS (Strapi, Sanity, Contentful), static site generators, or any backend that can receive HTTP requests.

Request Format

All requests are POST with JSON body:

POST https://your-endpoint.com/buzzrank-webhook
Content-Type: application/json
X-BuzzRank-Signature: <hmac-sha256-signature>

{
  "action": "verify" | "create_post" | "update_post" | "schedule_post" | "upload_media" | "get_post",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": { ... }
}

Signature Verification

If you configure a webhook secret, all requests are signed using HMAC-SHA256. The signature is in the X-BuzzRank-Signature header.

How to verify (Node.js example):

const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your handler:
app.post('/buzzrank-webhook', (req, res) => {
  const signature = req.headers['x-buzzrank-signature'];
  const payload = JSON.stringify(req.body);

  if (!verifySignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook...
});

Actions

verifyTest connection

Sent when testing the connection from BuzzRank. Return HTTP 200 to confirm the endpoint is working.

Request:

{
  "action": "verify",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {}
}

Response:

HTTP 200 OK
{ "success": true }
create_postCreate new article

Sent when publishing a new article. You must return the created post ID (and optionally the URL).

Request:

{
  "action": "create_post",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {
    "title": "How to Optimize Your Website for SEO",
    "content": "<h2>Introduction</h2><p>SEO is important...</p>",
    "slug": "how-to-optimize-website-seo",
    "excerpt": "Learn the best practices for SEO optimization...",
    "featuredImageUrl": "https://images.buzzrank.io/abc123.jpg",
    "metaTitle": "SEO Optimization Guide | Your Site",
    "metaDescription": "Complete guide to optimizing your website...",
    "status": "draft" | "publish" | "scheduled",
    "scheduledAt": "2026-01-15T09:00:00.000Z"
  }
}

Response (required):

HTTP 200 OK
{
  "id": "post-123",
  "url": "https://yoursite.com/blog/how-to-optimize-website-seo"
}
update_postUpdate existing article

Sent when updating an already published article. Only modified fields are included.

Request:

{
  "action": "update_post",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {
    "id": "post-123",
    "title": "Updated Title",
    "content": "<p>Updated content...</p>",
    "status": "publish"
  }
}

Response:

HTTP 200 OK
{ "success": true }
schedule_postSchedule article for future publishing

Request:

{
  "action": "schedule_post",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {
    "id": "post-123",
    "scheduledAt": "2026-01-15T09:00:00.000Z"
  }
}

Response:

HTTP 200 OK
{ "success": true }
upload_mediaUpload image/media

Sent when BuzzRank needs to upload an image. You should download the image from the provided URL and store it in your media library.

Request:

{
  "action": "upload_media",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {
    "imageUrl": "https://images.buzzrank.io/generated-image-abc123.jpg"
  }
}

Response (required):

HTTP 200 OK
{
  "id": "media-456",
  "url": "https://yoursite.com/uploads/image-abc123.jpg"
}
get_postRetrieve article details

Sent to check the status of a published article.

Request:

{
  "action": "get_post",
  "timestamp": "2026-01-11T12:00:00.000Z",
  "data": {
    "id": "post-123"
  }
}

Response:

HTTP 200 OK
{
  "id": "post-123",
  "url": "https://yoursite.com/blog/how-to-optimize-website-seo",
  "title": "How to Optimize Your Website for SEO",
  "content": "<h2>Introduction</h2><p>...</p>",
  "status": "publish",
  "publishedAt": "2026-01-11T12:00:00.000Z"
}

Error Handling

Return appropriate HTTP status codes for errors:

StatusMeaning
200Success
400Bad request (invalid data)
401Unauthorized (invalid signature)
404Post not found (for update/get)
500Server error

Example Implementation (Express.js)

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

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.BUZZRANK_WEBHOOK_SECRET;

// Verify signature middleware
function verifyBuzzRank(req, res, next) {
  const signature = req.headers['x-buzzrank-signature'];
  if (!WEBHOOK_SECRET || !signature) {
    return next(); // Skip if no secret configured
  }

  const payload = JSON.stringify(req.body);
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  next();
}

app.post('/buzzrank-webhook', verifyBuzzRank, async (req, res) => {
  const { action, data } = req.body;

  try {
    switch (action) {
      case 'verify':
        return res.json({ success: true });

      case 'create_post':
        const post = await createPostInYourCMS(data);
        return res.json({ id: post.id, url: post.url });

      case 'update_post':
        await updatePostInYourCMS(data.id, data);
        return res.json({ success: true });

      case 'schedule_post':
        await schedulePostInYourCMS(data.id, data.scheduledAt);
        return res.json({ success: true });

      case 'upload_media':
        const media = await uploadMediaToYourCMS(data.imageUrl);
        return res.json({ id: media.id, url: media.url });

      case 'get_post':
        const existing = await getPostFromYourCMS(data.id);
        if (!existing) return res.status(404).json({ error: 'Not found' });
        return res.json(existing);

      default:
        return res.status(400).json({ error: 'Unknown action' });
    }
  } catch (error) {
    console.error('Webhook error:', error);
    return res.status(500).json({ error: 'Internal error' });
  }
});

app.listen(3000);

Testing Your Webhook

You can test your webhook endpoint using curl:

# Test verify action
curl -X POST https://your-endpoint.com/buzzrank-webhook \
  -H "Content-Type: application/json" \
  -d '{"action": "verify", "timestamp": "2026-01-11T12:00:00.000Z", "data": {}}'

# Test with signature (replace SECRET with your webhook secret)
PAYLOAD='{"action":"verify","timestamp":"2026-01-11T12:00:00.000Z","data":{}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "YOUR_SECRET" | cut -d' ' -f2)

curl -X POST https://your-endpoint.com/buzzrank-webhook \
  -H "Content-Type: application/json" \
  -H "X-BuzzRank-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

Need Help?

If you need assistance implementing your webhook integration, contact us at support@buzzrank.io