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 nowEvents
article.status_changedEvery 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.publishedAn 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.revisedA revision landed (PR comment, chat, or API), with the summary of what changed.
topics.suggestedA topic-research run finished; new suggestions are waiting.
brand.crawledThe 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.