Docs / API

Webhooks

Instead of polling, register an HTTPS endpoint and Contentcron pushes events as they happen. Register via the API; the signing secret is returned once.

curl -X POST $BASE/api/v1/webhooks -H "$AUTH" \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com/hooks/contentcron",
       "events":["article.status_changed"]}'
# → { "webhook": { "id": …, "secret": "whsec_…" } }  ← store the secret now

Events

article.status_changed

Every pipeline transition — queued, researching, writing, draft, publishing, pr_open, merged, closed, failed — with the full article payload. Follow an article end-to-end from these alone.

article.published

An article was published — merged to your repo. Also powers the per-project post-publish webhook on the integrations page (point it at a deploy hook to rebuild your site).

article.revised

A revision landed (PR comment, chat, or API), with the summary of what changed.

topics.suggested

A topic-research run finished; new suggestions are waiting.

brand.crawled

The site crawl finished; the brand profile is ready.

Subscribe to specific events or omit events to receive everything. Deliveries retry automatically on non-2xx responses.

Payload

{
  "id": "6f0c…",                  // unique per event — dedupe on it
  "type": "article.status_changed",
  "createdAt": "2026-07-29T16:20:11Z",
  "data": { "id": "…", "status": "pr_open", "prUrl": "…", … }
}

Verifying signatures

Every delivery carries x-contentcron-signature: an HMAC-SHA256 of the raw request body with your endpoint's secret. Verify with a constant-time compare before trusting the payload:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, header: string, secret: string) {
  const expected = "sha256=" +
    createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(header);
  return a.length === b.length && timingSafeEqual(a, b);
}

Use the raw body bytes — parsing and re-serializing JSON first will break the MAC. Rotate a compromised secret by deleting the endpoint and registering it again.