Webhooks

Webhooks in jekcms are inbound: external tools push content and commands into your site. An n8n workflow finishes writing an article — it POSTs the result to your site and the post appears as a draft, a scheduled post, or goes live, whichever you asked for. The same endpoints drive media uploads, bulk imports and status checks.

For the reverse direction (jekcms notifying other services when something happens), pair these endpoints with an n8n polling trigger or the REST API — see the API reference for read endpoints.

Endpoints

All webhook calls are POST https://yoursite.com/api/v1/webhook/{action} with a JSON body. Supported actions:

  • publish — create a post and publish it immediately
  • schedule — create a post scheduled for a future date
  • draft — create a draft post
  • update — update an existing post
  • delete — delete a post
  • media — upload media from a URL
  • media-base64 — upload media from base64 data
  • bulk-publish — publish multiple posts in one call
  • bulk-import — import multiple posts from RSS/JSON
  • ai-enhance — enrich content with AI metadata
  • status — get a post's current status
  • check-source — check whether a source URL was already imported
  • trigger — fire a custom automation trigger

Authentication

Two ways to authenticate a webhook call; either one is enough:

  1. API key — send a key created under Admin → API Keys (admin/api-keys.php) as a Bearer token. Recommended for n8n and Zapier, where a header field is easy to configure.
  2. HMAC signature — define N8N_WEBHOOK_SECRET in your config, then sign every request: the X-Webhook-Signature header (also accepted: X-N8N-Signature) must contain the HMAC-SHA256 of the raw request body using the secret as key. If neither an API key nor a valid signature is present, the call is rejected with 401 Invalid webhook signature.

Signing examples (sender side)

PHP

$body = json_encode(['title' => 'Hello', 'content' => '...']);
$signature = hash_hmac('sha256', $body, getenv('JEKCMS_WEBHOOK_SECRET'));

$ch = curl_init('https://yoursite.com/api/v1/webhook/draft');
curl_setopt_array($ch, [
    CURLOPT_POST       => true,
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Webhook-Signature: ' . $signature,
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);

Node.js

const crypto = require('crypto');

const body = JSON.stringify({ title: 'Hello', content: '...' });
const signature = crypto
    .createHmac('sha256', process.env.JEKCMS_WEBHOOK_SECRET)
    .update(body)
    .digest('hex');

await fetch('https://yoursite.com/api/v1/webhook/draft', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-Webhook-Signature': signature,
    },
    body,
});

Python

import hmac, hashlib, json, os, requests

body = json.dumps({'title': 'Hello', 'content': '...'})
signature = hmac.new(
    os.environ['JEKCMS_WEBHOOK_SECRET'].encode(),
    body.encode(),
    hashlib.sha256,
).hexdigest()

requests.post(
    'https://yoursite.com/api/v1/webhook/draft',
    data=body,
    headers={
        'Content-Type': 'application/json',
        'X-Webhook-Signature': signature,
    },
)

The signature is computed over the exact bytes you send — serialize once and sign that string; re-encoding on the way out will invalidate it.

Editorial safety

If you want a human in the loop, target draft (or schedule) instead of publish: content lands in the admin as a normal draft and goes live only when an editor publishes it. The content queue (see Content Queue) gives you a review pipeline on top.

n8n quick start

  1. Create an API key under Admin → API Keys.
  2. In n8n, add an HTTP Request node: method POST, URL https://yoursite.com/api/v1/webhook/draft, authentication Bearer token with your key.
  3. Map your workflow fields into the JSON body (title, content, category, tags, featured_image…).
  4. Run the workflow — the post appears in your admin as a draft.

Be the first to know

New features, release notes & CMS guides — a couple of emails a month, no spam.