Citapult

Send articles to your system by webhook.

For any other CMS and any workflow of your own: Citapult sends each published article as JSON to a URL you choose.

Updated

What you need

  • A publicly reachable HTTPS URL that accepts POST requests with JSON.
  • A response with a 2xx status within 20 seconds. Citapult doesn't read the response body.
  • Optionally, a token your receiver uses to tell that a request comes from Citapult.

Set it up

  1. 1. Build the receiver

    Set up an endpoint that accepts POST requests and answers with a 2xx status. If you use a token, check it in the Authorization: Bearer <token> header. Citapult doesn't follow redirects, so enter the final URL, not one that redirects.

  2. 2. Add the integration

    In Citapult, open Settings → Integrations, pick Webhook under “Type” and enter the URL, plus your token under “Token (optional)”. The token is stored encrypted and never shown again.

  3. 3. Test it

    Click “Test” next to the integration. Citapult then sends the test event without an article. If your receiver answers with 2xx, you'll see “The receiver answered.”

  4. 4. Publish an article

    Open a finished article and click “Publish”. Until your receiver has accepted the article once with a 2xx, the publish_articles event arrives; after that, every send is update_article.

  5. 5. Optional: publish automatically

    Turn on “Publish automatically” under Integrations. Articles marked “Needs review” then go out to all integrations on their scheduled day without a click. You set the time in the calendar under “Schedule”.

The events

Every request is a JSON object with event_type, timestamp and data, sent with Content-Type: application/json.

  • publish_articles: until your receiver has accepted the article once with a 2xx. The article is in data.articles, a list with one entry.
  • update_article: every send after that. The article is in data.article.
  • test: a click on “Test”, with an empty data.
publish_articles
{
  "event_type": "publish_articles",
  "timestamp": "2026-10-08T08:00:04.512Z",
  "data": {
    "articles": [
      {
        "id": "9b2f4c1e-…",
        "title": "How to make a sourdough starter",
        "slug": "sourdough-starter",
        "content_html": "<p>…</p>",
        "meta_description": "…",
        "language": "en-US",
        …
      }
    ]
  }
}
update_article
{
  "event_type": "update_article",
  "timestamp": "2026-10-09T14:21:37.090Z",
  "data": {
    "article": { … }
  }
}

The fields of an article

Every field is always there: a missing value is null, a missing list is empty. Your receiver can validate every request against the JSON Schema.

FieldContents
idThe article's ID, the same on every update
titleThe title, meant as the H1
slugThe last part of the URL, fixed after the first publish
content_htmlThe article text as HTML, without the H1. Raw HTML in the text arrives as text, only YouTube embeds stay.
content_markdownThe same text as Markdown
meta_title, meta_descriptionMeta title and meta description
image_url, image_altThe featured image and its alt text
languageThe article's language and country, like en-US
tagsA list with the article's main keyword
json_ldThe structured data as a list, one application/ld+json script each
sourcesThe sources, with url and title
authorName, plus role and short bio if set in the settings, or null
created_atWhen the article was created, in ISO format

Errors and retries

If your receiver doesn't answer with 2xx, or not within 20 seconds, the reason shows in the list below the button on the article, like “failed: HTTP 500”. The article's status doesn't change then.

  • “Publish” or “Update” sends it again, to every integration of the website. The button reads “Update” once any integration has accepted the article.
  • With “Publish automatically” on, Citapult tries again every 15 minutes while the article is at “Needs review”, until the end of the day after the scheduled day (UTC).
  • So the same article can arrive more than once, even more than once as publish_articles. Treat an id you already know as an update, not a new post.

Removing the integration

If you add the integration again later, every article arrives as publish_articles again on its next send. If your receiver recognizes the id, that doesn't create a duplicate post.

Errors and questions

“Enter a publicly reachable HTTPS address.”

The URL has to start with https:// and be reachable from the internet. Citapult doesn't accept URLs on a local network.

“Credentials don't belong in the URL.”

The URL contains a username and password, like https://name:password@…. Take them out and use the “Token (optional)” field instead. The token arrives as Authorization: Bearer <token>.

“The test failed (HTTP 401).”

Your receiver rejected the token. Check that it expects the same token and reads it from the Authorization header after Bearer .

“… (HTTP 301)” or another 3xx status

The URL redirects, to a version with a trailing slash for example. Citapult doesn't follow redirects, so the token never ends up on another server. Enter the target URL.

“… (ENOTFOUND)” or “… (ECONNREFUSED)”

The host name doesn't exist, or the server refuses the connection. Check the URL and that your receiver is running.

The receiver takes longer than 20 seconds

Citapult gives up after 20 seconds and shows the error below the button. Answer with 2xx first, then process the article.

How do I check that a request comes from Citapult?

By the token: Citapult sends it with every request as Authorization: Bearer <token>. There's no signature, so use a long, random token.

How publishing works

Three days of Pro for $1.

Then Regular price$199 now$99 a month per website. Cancel anytime before.