> ## Documentation Index
> Fetch the complete documentation index at: https://developers.semji.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Content published webhook

> The content_published webhook: Semji notifies your endpoint when an editor marks a content as published, so you can distribute it to your CMS or automation tools — with ready-made Make and N8n templates.

When an editor clicks **Mark as published** in Semji, Semji sends a
`content_published` webhook to the URL you configured. Use it to push the
published article to your CMS, or to trigger downstream automations
(dashboards, tasks, notifications) — no polling, no copy-paste.

<Note>
  `content_published` fires **after** publication (the editor decided the content
  is live). It is separate from the [Send to CMS webhook](/integrations/send-to-cms-webhook)
  (`content_staged`), which pushes a **draft** to your CMS *before* publication.
  Both can be configured on the same workspace.
</Note>

## Prerequisites

* An HTTPS endpoint reachable from the public internet — either your own, or a
  scenario URL from a no-code platform (Make, Zapier, N8n).
* A workspace where you can reach **Settings** (to add the webhook).

## How it works

<Steps>
  <Step title="Add the webhook in Semji">
    In the app, go to **Settings > General**, click **Add a Webhook**, and paste
    your endpoint (or automation scenario) URL.
  </Step>

  <Step title="An editor marks a content as published">
    They fill in the publication URL and date (backdating works, in the app and
    via the API's `publishedAt`).
  </Step>

  <Step title="Semji POSTs the content_published event">
    A single `POST` with the content payload lands on your endpoint. Respond with
    a `2xx` immediately and process asynchronously.
  </Step>
</Steps>

## The payload Semji sends

```json title="content_published payload" theme={null}
{
  "event_type": "content_published",
  "occurred_at": "2026-06-10T14:32:05+00:00",
  "data": {
    "id": "7c4a1f08b29d",
    "title": "How to choose a CRM in 2026",
    "html": "<h1>How to choose a CRM in 2026</h1><p>…</p>",
    "meta_description": "A practical guide to picking the right CRM…",
    "content_score": 82,
    "words_count": 1450,
    "published_at": "2026-06-10T14:32:04+00:00",
    "published_by": { "id": "f2a81c05d943", "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com" },
    "content_status": { "id": "41f8a2c5e7d3", "label": "published", "color": "#10b981" },
    "page": {
      "id": "5e8d203c7f1a",
      "url": "https://example.com/blog/choose-a-crm",
      "is_existing_content": true,
      "last_status_code": 200
    },
    "page_focus_keyword": { "keyword": "best crm for small business", "search_volume": 5400, "position": 8 },
    "workspace": { "id": "89b0f07aade2", "name": "Acme Blog", "website_url": "https://example.com" },
    "organization": { "id": "c61d3e84f207", "name": "Acme" }
  }
}
```

<ResponseField name="event_type" type="string">
  Always `content_published` for this webhook.
</ResponseField>

<ResponseField name="data" type="object">
  The published content and its context: `title`, sanitized `html`, plain `text`,
  `meta_description`, `content_score`, `words_count`, `published_at`,
  `published_by`, `content_status`, `page` (with the live `url`),
  `page_focus_keyword` (with `search_volume`), plus `workspace` and `organization`.
  IDs are 12-char public IDs.
</ResponseField>

Three things to know:

* `data.html` is **already sanitized** — editor annotations are stripped, it is
  equivalent to the API's `htmlSanitized` field. Push it to your CMS as-is.
* `data.id` is the content ID, directly usable with
  [`GET /v1/contents/{contentId}`](/api-reference/contents/get-content-details).
* Delivery is a **single POST** — no signature, no retry on failure. Respond
  `2xx` immediately and process asynchronously.

<Warning>
  The webhook is **not signed**: anyone who discovers your endpoint URL could
  forge a payload. Treat it as a **trigger** — re-fetch the content by ID with
  your API key before touching your CMS, and drop the event if the content
  doesn't exist or isn't published.
</Warning>

## No-code templates

Prefer not to write code? Import one of these ready-made scenarios and point it
at WordPress (adapt the CMS step for another platform):

<CardGroup cols={2}>
  <Card title="Make template" icon="https://mintcdn.com/semji/3quSdqkylJbDAJnr/images/icons/phosphor/plugs-connected.svg?fit=max&auto=format&n=3quSdqkylJbDAJnr&q=85&s=d3635d3fae6c7dea56f3a482699301eb" href="https://drive.google.com/file/d/1ZJMnbwcguYeOwIUw9pIRI2AQLN0Yy7QV/view?usp=sharing" width="256" height="256" data-path="images/icons/phosphor/plugs-connected.svg">
    A Make scenario that receives the webhook and creates the post in WordPress.
  </Card>

  <Card title="N8n WordPress template" icon="https://mintcdn.com/semji/3quSdqkylJbDAJnr/images/icons/phosphor/plugs-connected.svg?fit=max&auto=format&n=3quSdqkylJbDAJnr&q=85&s=d3635d3fae6c7dea56f3a482699301eb" href="https://drive.google.com/file/d/136_mfdhWA9dSwc4TJPvmbOUkOdCBwCzZ/view?usp=sharing" width="256" height="256" data-path="images/icons/phosphor/plugs-connected.svg">
    An N8n workflow with a POST webhook trigger that routes the content to WordPress.
  </Card>
</CardGroup>

The scenario URL these tools give you is what you paste into **Settings > General > Add a Webhook**.

## Use cases

* Publish or update the article in your CMS (WordPress, Contentful, Webflow…).
* Auto-populate a Google Sheets dashboard with the SEO metrics.
* Create a follow-up task (Asana, Jira) for the marketing team.
* Notify a Slack or Teams channel on publication.
* Cross-post to social (X, LinkedIn).

## Troubleshooting

<AccordionGroup>
  <Accordion title="My endpoint never receives anything">
    Check the webhook URL in **Settings > General**, and that an editor actually
    clicked **Mark as published** (the event only fires on publication). The URL
    must be a public HTTPS endpoint reachable from Semji.
  </Accordion>

  <Accordion title="I got the event but the content looks wrong or missing">
    Delivery is a single unsigned POST — treat it as a trigger and re-fetch the
    content with [`GET /v1/contents/{contentId}`](/api-reference/contents/get-content-details)
    using your API key before writing to your CMS.
  </Accordion>
</AccordionGroup>

## Related

* [Send to CMS webhook](/integrations/send-to-cms-webhook) — push a **draft** to
  your CMS before publication (`content_staged`).
* [Sync drafts to your CMS](/guides/sync-drafts-to-cms) — the pull-based
  publishing flow, and when to prefer it over this webhook.
* [Authentication](/api-reference/authentication) — API keys for re-fetching content.
