webhook logo

Custom webhook integration

Connect Auto SEO to Custom webhook

If your CMS isn't natively supported yet, the webhook integration covers it. Auto SEO POSTs a JSON payload for each article; your endpoint does the rest.

  1. 1

    Create an HTTPS endpoint

    Any framework or platform works — Next.js Route Handler, Express, Cloudflare Worker, Lambda, even a tiny Cloud Function. It needs to accept POST and return 2xx on success.

  2. 2

    Set the shared secret

    Pick a strong random string. Put it in your env as AUTOSEO_WEBHOOK_SECRET. Add it to the Auto SEO dashboard under Integrations → Webhook.

  3. 3

    Verify the signature on every request

    Auto SEO sends an x-autoseo-signature header (HMAC-SHA256 of the raw body). Reject any request whose signature doesn't match — never trust the payload alone.

  4. 4

    Persist the article

    Read the nested article object. Map article.content to your HTML body and preserve draft status. Upsert using article.externalId or article.slug so repeated deliveries update one post. Acknowledge connection.test without creating any content, then return 2xx for successful deliveries.

  5. 5

    Handle queued retries

    Articles sent through the publish queue retry after 5 minutes, 30 minutes, and 2 hours, up to four attempts in total. Direct connection tests do not use this queue. Inspect failed delivery details and retry after fixing the receiver; retries are finite.

Example payload / snippet

Example payload

{
  "type": "article.published",
  "version": 1,
  "timestamp": "2026-10-04T08:00:00Z",
  "test": false,
  "article": {
    "externalId": "article-example",
    "slug": "seo-publishing-guide",
    "title": "An SEO publishing guide",
    "content": "<p>Reviewed article HTML goes here.</p>",
    "excerpt": "An example article summary.",
    "metaTitle": "An SEO publishing guide",
    "metaDescription": "A practical guide to reviewing and publishing SEO content.",
    "status": "published",
    "tags": ["seo", "publishing"]
  }
}

Signature verification

// Node.js example
import crypto from "node:crypto";
// The header is "sha256=<hex>" — strip the prefix before comparing.
const sig = (req.headers.get("x-autoseo-signature") || "").replace(/^sha256=/, "");
const body = await req.text(); // raw body before parsing
const expected = crypto
  .createHmac("sha256", process.env.AUTOSEO_WEBHOOK_SECRET)
  .update(body)
  .digest("hex");
if (!/^[a-f0-9]{64}$/i.test(sig) ||
    !crypto.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"))) {
  return new Response("Forbidden", { status: 403 });
}
const payload = JSON.parse(body);
if (payload.type === "connection.test" || payload.test === true) {
  return Response.json({ ok: true }); // never create a post for a connection test
}
if (payload.type !== "article.published" || !payload.article) {
  return new Response("Unsupported event", { status: 400 });
}
// Upsert payload.article using externalId (or slug), then return 2xx.
// Keep articles whose status is "draft" unpublished.

What gets published

  • Nested article object containing the title, HTML content, and URL slug.
  • Optional heroImage URL, excerpt, tags, category, and publication status.
  • Optional metaTitle, metaDescription, canonical, ogImage, and keywords.
  • Optional structuredData objects and jsonLd markup when supplied by the article.
  • Stable externalId when available, for receiver-side deduplication.

Troubleshooting

For signature mismatches, hash the raw body bytes using the same secret saved in AutoSEO. Allow X-AutoSEO-Signature through your proxy. Read the event from type and content from article.content. Use X-AutoSEO-Delivery to identify a delivery in receiver logs; repeated publishing should update the same destination post.

Plans are $39/mo per website, charged when you subscribe; cancel anytime, 30-day money-back guarantee. Review the plan and billing terms before checkout.