Custom webhook
Receive every article as JSON and publish it on any platform.
A webhook connects ProgSEO to any platform: Next.js, Webflow via your own middleware, a headless CMS, a Zapier/Make scenario, or your own backend. When something happens to an article, ProgSEO sends a POST request with a JSON payload to your URL.
Set up a webhook
- 1
Create an endpoint
Create a URL on your server that accepts POST requests with a JSON body.
- 2
Add it to ProgSEO
Open Integrate → Webhooks, paste the Webhook URL, set a Webhook Secret and press Save.
- 3
Verify requests
Every request carries
Authorization: Bearer your_secret. Reject requests where it doesn't match. - 4
Acknowledge
Return a
2xxstatus once you have stored the article. Other responses are recorded as failed deliveries.
Events
| Event | When it fires |
|---|---|
post_created | A new article is generated and published. |
post_updated | An article is edited and republished, or a change request is accepted. |
post_deleted | Reserved for future use — not sent yet. |
post_created
{
"event": "post_created",
"timestamp": "2026-03-26T12:00:00Z",
"site": "your-site-slug",
"data": {
"slug": "how-to-optimize-your-landing-page",
"title": "How to Optimize Your Landing Page",
"description": "A guide to...",
"author": "Editorial Team",
"tags": ["seo", "landing-pages"],
"publishedAt": "2026-03-26",
"readingTime": "8 min read",
"blocks": [
{ "type": "hero", "title": "...", "subtitle": "..." },
{ "type": "text", "content": "..." }
]
}
}post_updated
{
"event": "post_updated",
"timestamp": "2026-03-26T14:30:00Z",
"site": "your-site-slug",
"data": {
"slug": "how-to-optimize-your-landing-page",
"oldPost": { "slug": "...", "title": "...", "blocks": [ ... ] },
"newPost": { "slug": "...", "title": "...", "blocks": [ ... ] },
"updatedFields": ["blocks"],
"updatedAt": "2026-03-26T14:30:00Z",
"changeRequestId": "cr_123"
}
}changeRequestId is only present when the update came from an accepted change request.
Content blocks
Article content is an ordered blocks array. Each block has a type: hero, text, heading, list, image, table, quote, code, divider, faq, features, stats, cta, youtube and author. Render the types you support and skip the rest. If you'd rather receive ready-made HTML-like content, look at the Markdown and TSX exports.
Example handler (Node.js)
app.post("/api/webhook", (req, res) => {
if (req.headers["authorization"] !== "Bearer " + process.env.WEBHOOK_SECRET) {
return res.status(401).json({ error: "Unauthorized" });
}
const { event, data } = req.body;
switch (event) {
case "post_created":
// save data.slug, data.title, data.blocks ...
break;
case "post_updated":
// replace the post matching data.slug with data.newPost
break;
}
res.status(200).json({ received: true });
});Delivery log and retries
Once a webhook URL is saved, Integrate → Webhooks shows recent deliveries with the status code your server returned. Failed deliveries can be retried from there after you fix the endpoint.
Tip
Use the article slug as the unique key on your side. Both post_created and post_updated can then be handled as an upsert.
Still stuck? Email [email protected] and we'll help.