Contensa
Features
PricingBlogAbout
Log inStart free
Back to Blog
For developers

Webhooks in Contensa: Real-Time Content Sync with Any Platform

Learn how to use Contensa's webhook system to trigger real-time builds, sync content to external systems, and automate your content workflow.

Jan 28, 2026
•
8 min read
WebhooksAutomationIntegrationDeveloper Guide
A

Alex Rodriguez

Senior Software Engineer

Webhooks in Contensa: Real-Time Content Sync with Any Platform

Webhooks in Contensa: Real-Time Content Sync with Any Platform

Static generation is great for performance. But it creates a problem: when content changes in your CMS, your site does not update until the next build.

Webhooks solve this. When content is published, updated, or deleted in Contensa, a webhook fires — triggering a rebuild, syncing to an external system, or running any automation you need.

What Are Webhooks?

A webhook is an HTTP POST request that Contensa sends to a URL you specify when something happens in your workspace. The request includes a JSON payload describing what changed.

You configure the URL to send the request to, which events trigger the webhook (publish, update, delete), and which content types to watch.

Setting Up a Webhook in Contensa

  1. Go to your workspace Settings → Webhooks
  2. Click Add webhook
  3. Enter your endpoint URL
  4. Select the events to trigger on:
    • entry.publish
      — when an entry is published
    • entry.unpublish
      — when an entry is unpublished
    • entry.update
      — when a draft is updated
    • entry.delete
      — when an entry is deleted
  5. Optionally filter by content type
  6. Save — Contensa sends a test request to verify your endpoint

The Webhook Payload

json
{ "event": "entry.publish", "timestamp": "2026-01-28T10:30:00.000Z", "workspaceId": "ws_abc123", "entry": { "id": "entry_xyz789", "contentTypeId": "blog-post-type-id", "contentTypeName": "BlogPost", "status": "published", "data": { "title": "My New Blog Post", "slug": "my-new-blog-post", "publishedAt": "2026-01-28T10:30:00.000Z" } } }

Verifying Webhook Signatures

Contensa signs every webhook request with HMAC-SHA256. Always verify this before processing.

typescript
import crypto from 'crypto'; function verifyWebhookSignature( payload: string, signature: string, secret: string ): boolean { const expectedSignature = `sha256=${crypto .createHmac('sha256', secret) .update(payload) .digest('hex')}`; return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); }

The signature is in the

X-Contensa-Signature
header.

Use Case 1: Trigger a Vercel Rebuild

Create a Next.js API route at

app/api/webhooks/contensa/route.ts
:

typescript
import { NextRequest, NextResponse } from 'next/server'; import crypto from 'crypto'; const WEBHOOK_SECRET = process.env.CONTENSA_WEBHOOK_SECRET!; const VERCEL_DEPLOY_HOOK = process.env.VERCEL_DEPLOY_HOOK_URL!; export async function POST(request: NextRequest) { const body = await request.text(); const signature = request.headers.get('x-contensa-signature') ?? ''; const expectedSig = `sha256=${crypto .createHmac('sha256', WEBHOOK_SECRET) .update(body) .digest('hex')}`; if (signature !== expectedSig) { return NextResponse.json({ error: 'Invalid signature' }, { status: 401 }); } const payload = JSON.parse(body); if (['entry.publish', 'entry.unpublish'].includes(payload.event)) { await fetch(VERCEL_DEPLOY_HOOK, { method: 'POST' }); } return NextResponse.json({ received: true }); }

Now every time you publish content in Contensa, your Vercel site rebuilds automatically.

Use Case 2: Sync to Algolia Search

typescript
import algoliasearch from 'algoliasearch'; const algolia = algoliasearch( process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY! ); const index = algolia.initIndex('blog_posts'); // Inside your webhook handler, after signature verification: const payload = JSON.parse(body); if (payload.entry.contentTypeName !== 'BlogPost') { return NextResponse.json({ skipped: true }); } switch (payload.event) { case 'entry.publish': await index.saveObject({ objectID: payload.entry.id, title: payload.entry.data.title, slug: payload.entry.data.slug, excerpt: payload.entry.data.excerpt, }); break; case 'entry.unpublish': case 'entry.delete': await index.deleteObject(payload.entry.id); break; }

Use Case 3: Slack Notifications

Get notified in Slack when content is published:

typescript
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL!; if (payload.event === 'entry.publish') { await fetch(SLACK_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: `New content published: *${payload.entry.data.title}*`, blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `*${payload.entry.contentTypeName}* published: <https://yoursite.com/blog/${payload.entry.data.slug}|${payload.entry.data.title}>`, }, }, ], }), }); }

Handling Webhook Failures

Contensa retries failed webhook deliveries with exponential backoff:

  • Immediate retry on failure
  • 5 minutes after first failure
  • 30 minutes after second failure
  • 2 hours after third failure

Your endpoint should return a 2xx status code within 10 seconds. For long-running operations, return 200 immediately and process asynchronously:

typescript
export async function POST(request: NextRequest) { // Verify signature... const payload = JSON.parse(body); // Return immediately const response = NextResponse.json({ received: true }); // Process asynchronously (use a queue in production) processWebhookAsync(payload).catch(console.error); return response; }

Best Practices

Use a queue for reliability. For production systems, push webhook events to a queue (SQS, BullMQ, Inngest) rather than processing synchronously. This handles retries, backpressure, and failures gracefully.

Log everything. Store webhook events in a database for debugging and auditing. When something goes wrong, you want to know exactly what was received and when.

Be idempotent. Webhooks can be delivered more than once. Design your handlers so that processing the same event twice has no negative effect.

Filter early. Return 200 immediately for events you do not care about. Do not make Contensa wait while you decide whether to process an event.

The Result

With webhooks properly configured, your content workflow becomes fully automated:

  1. Content editor publishes a blog post in Contensa
  2. Webhook fires to your endpoint
  3. Vercel rebuild triggers — new post is live within 60 seconds
  4. Algolia index updates — post is searchable immediately
  5. Slack notification fires — team knows content is live

No manual steps. No delays. Content published in Contensa is live everywhere within minutes.


Start your free Contensa workspace and connect your first webhook in minutes.

Share Article

About the Author

A

Alex Rodriguez

Senior Software Engineer

Alex is a senior software engineer specializing in GraphQL and modern API architectures. He's been building scalable systems for over a decade.

Related Articles

View all articles
Building Dynamic Apps with Contensa's GraphQL API
For developers

Building Dynamic Apps with Contensa's GraphQL API

A comprehensive guide to integrating Contensa's powerful GraphQL API into your applications with real-world examples and code snippets.

Jan 5, 2026
•
10 min read
Building a Next.js Blog with Contensa in Under 30 Minutes
For developers

Building a Next.js Blog with Contensa in Under 30 Minutes

A step-by-step tutorial for building a fully functional Next.js blog powered by Contensa's GraphQL API — from workspace setup to deployed site.

Feb 1, 2026
•
12 min read
Getting Started with Contensa: Your Complete Setup Guide
Technical

Getting Started with Contensa: Your Complete Setup Guide

Learn how to set up Contensa CMS in minutes with this step-by-step guide covering installation, configuration, and fetching your first content.

Jan 15, 2026
•
8 min read