Webhooks
Receive real-time article events from MisarBlog via outbound HTTP POST webhooks.
Overview
MisarBlog sends an HTTP POST request to your configured webhook URL whenever an article is published, updated, or deleted. Use webhooks to sync content to third-party platforms, trigger automations in n8n or Zapier, or update your own backend.
Webhook URL configuration
Configure your webhook URL at misar.blog/dashboard/integrations. Only HTTPS URLs are accepted.
Events
| Event | Description |
|---|---|
article.published | Fires when a new article is published or a draft goes live. |
article.updated | Fires when a published article's content is updated. |
article.deleted | Fires when a published article is permanently deleted. |
Request Headers
Every webhook request includes the following headers:
| Header | Value | Description |
|---|---|---|
Content-Type | application/json | Payload encoding |
User-Agent | MisarBlog-Webhook/1.0 | Identifies the sender |
X-Webhook-Event | e.g. article.published | Event name — use for routing |
X-Webhook-Secret | shared secret string | Shared secret for lightweight verification |
X-Webhook-Secret
X-Webhook-Secret is a platform-level shared secret. It is not per-user and is not a cryptographic HMAC signature. Treat it as a lightweight guard. For production, verify that X-Webhook-Event matches the event field in the payload body.
Payload Structure
All three events share the same JSON shape. The event field identifies which event fired.
{
"event": "article.published",
"timestamp": "2026-04-21T10:00:00.000Z",
"article": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "my-first-article",
"title": "My First Article",
"excerpt": "A brief summary of the article.",
"content_html": "<p>Full HTML content…</p>",
"tags": [
"writing",
"productivity"
],
"published_at": "2026-04-21T10:00:00.000Z",
"updated_at": "2026-04-21T10:00:00.000Z",
"canonical_url": "https://www.misar.blog/@username/articles/my-first-article"
},
"author": {
"username": "mrgulshanyadav",
"display_name": "mrgulshanyadav"
}
}Top-level fields
event"article.published" | "article.updated" | "article.deleted"The event that triggered this webhook.
timestampstringISO 8601 UTC timestamp of when the event was fired, e.g. "2026-04-21T10:00:00.000Z".
articleobjectArticle data at the time of the event. See fields below.
authorobjectThe article's author. See fields below.
article object
article.idstringUUID of the article. Use this as your idempotency key.
article.slugstringURL slug, e.g. "my-first-article".
article.titlestringArticle title.
article.excerptstring | nullShort description shown in previews and search results.
article.content_htmlstring | nullFull rendered HTML body of the article. null on article.deleted.
article.content_markdownstring | nullThe article body as clean Markdown — the authoritative source. Consumers should prefer this over content_html when rendering.
article.visibility"public" | "subscribers" | "paid" | "private" | "webhook_only"The article's visibility. webhook_only articles are delivered here for cross-platform sync and are not public on misar.blog.
article.tagsstring[] | nullArray of tag slugs attached to the article.
article.published_atstring | nullISO 8601 UTC timestamp when the article was first published.
article.updated_atstring | nullISO 8601 UTC timestamp of the last content update.
article.canonical_urlstring | nullCanonical URL, e.g. "https://www.misar.blog/@username/articles/my-first-article".
article.featured_image_urlstring | nullURL of the article's cover image. Present only if a cover image is set.
article.featured_image_credit_namestring | nullCredit name for the cover image (e.g. Unsplash photographer name).
article.featured_image_credit_urlstring | nullCredit URL for the cover image.
article.featured_image_source"upload" | "ai" | "unsplash" | "pexels" | nullHow the cover image was sourced.
article.visibility"public" | "subscribers" | "paid" | "private" | "webhook_only"Article visibility level at time of event.
author object
author.usernamestringAuthor's unique username on MisarBlog.
author.display_namestring | nullAuthor's display name. May be null if not set.
Event Variants
{
"event": "article.published",
"timestamp": "2026-04-21T10:00:00.000Z",
"article": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "my-first-article",
"title": "My First Article",
"excerpt": "A brief summary of the article.",
"content_html": "<p>Full HTML content…</p>",
"tags": ["writing", "productivity"],
"published_at": "2026-04-21T10:00:00.000Z",
"updated_at": "2026-04-21T10:00:00.000Z",
"canonical_url": "https://www.misar.blog/@username/articles/my-first-article"
},
"author": {
"username": "mrgulshanyadav",
"display_name": "mrgulshanyadav"
}
}{
"event": "article.updated",
"timestamp": "2026-04-22T14:30:00.000Z",
"article": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "my-first-article",
"title": "My First Article (Revised)",
"excerpt": "Updated summary.",
"content_html": "<p>Updated HTML content…</p>",
"tags": ["writing", "productivity", "tips"],
"published_at": "2026-04-21T10:00:00.000Z",
"updated_at": "2026-04-22T14:30:00.000Z",
"canonical_url": "https://www.misar.blog/@username/articles/my-first-article"
},
"author": {
"username": "mrgulshanyadav",
"display_name": "mrgulshanyadav"
}
}{
"event": "article.deleted",
"timestamp": "2026-04-23T09:00:00.000Z",
"article": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "my-first-article",
"title": "My First Article",
"excerpt": null,
"content_html": null,
"tags": null,
"published_at": "2026-04-21T10:00:00.000Z",
"updated_at": "2026-04-23T09:00:00.000Z",
"canonical_url": null
},
"author": {
"username": "mrgulshanyadav",
"display_name": "mrgulshanyadav"
}
}Delivery Behavior
| Property | Value |
|---|---|
| HTTP method | POST |
| Content-Type | application/json |
| Timeout | 10 seconds |
| Retries | None — fire-and-forget |
| Security | HTTPS only; private IPs, localhost, and cloud metadata endpoints are blocked |
Idempotency tip
Always use article.id as your idempotency key. If your endpoint receives the same event twice, skip processing if you've already handled that id + event combination.
Respond Quickly
Return a 2xx status code within 10 seconds. Any non-2xx response or timeout is logged server-side but not retried. If your processing is slow, acknowledge immediately and queue the work:
export async function POST(req: Request) {
const payload = await req.json();
await queue.push(payload); // enqueue for background processing
return Response.json({ ok: true }); // respond immediately
}TypeScript Types
export interface WebhookPayload {
event: "article.published" | "article.updated" | "article.deleted";
timestamp: string;
article: {
id: string;
slug: string;
title: string;
excerpt: string | null;
content_html: string | null;
tags: string[] | null;
published_at: string | null;
updated_at: string | null;
canonical_url: string | null;
featured_image_url?: string | null;
featured_image_credit_name?: string | null;
featured_image_credit_url?: string | null;
featured_image_source?: "upload" | "ai" | "unsplash" | "pexels" | null;
visibility?: "public" | "subscribers" | "paid" | "private" | "webhook_only";
};
author: {
username: string;
display_name: string | null;
};
}Test Your Endpoint
Use webhook.site to inspect live payloads before wiring up your automation:
Get a test URL
Go to webhook.site and copy your unique URL.
Configure MisarBlog
Paste the URL into misar.blog/dashboard/integrations and click Save.
Trigger an event
Publish or update an article from your dashboard.
Inspect the payload
Return to webhook.site and view the full request headers and JSON body.
Integration Guides
For step-by-step setup with n8n, Zapier, and Make, see Integrations.