The publish API endpoint is POST /api/v1/posts/publish-task. It accepts JSON with title, content, author_id, category, featured_image (a URL), and an optional scheduled_at ISO 8601 timestamp. The API key goes in the X-API-Key header. Successful creation returns the new post's ID and public URL.

Minimal n8n Workflow Structure

In n8n, the minimal working workflow has four nodes: an HTTP Request to fetch source content (from OpenAI, an RSS feed, or your own source), a Code node to format the payload, an HTTP Request to call the JekCMS API, and an IF node to route errors to a Slack notification or retry queue. The entire flow completes in under two seconds per post under normal conditions.

Media Handling at Scale

Media handling deserves careful attention. When you pass a featured_image URL, JekCMS fetches it synchronously during the API request, converts it to AVIF, and stores it locally. If the source URL is slow to respond, your entire API request blocks. For high-volume pipelines, pre-upload images to your JekCMS install using the POST /api/v1/media/upload-from-url endpoint and pass the resulting media ID rather than a URL.

Real-World Numbers

We run approximately 600 automated posts per month across three sites using this workflow. The failure rate is under 0.3%, and every failure is a network timeout on the source content fetch, not a JekCMS API error. The endpoint itself has had 100% uptime over the eight-month period covered in this report.

Complete n8n Node Configuration

Here is the exact HTTP Request node configuration for the publish call. The Content-Type header must be application/json, and the API key must go in the X-API-Key header — not as a query parameter, which was deprecated in v1.5.0 for security reasons.

// n8n HTTP Request Node Settings
Method: POST
URL: https://yoursite.com/api/v1/posts/publish-task
Authentication: None (handled via header)
Headers:
 X-API-Key: {{ $credentials.jekcmsApiKey }}
 Content-Type: application/json
Body (JSON):
{
 "title": "{{ $json.title }}",
 "content": "{{ $json.content }}",
 "author_id": 2,
 "category": "{{ $json.category }}",
 "featured_image": "{{ $json.image_url }}",
 "image_alt_text": "{{ $json.image_alt }}",
 "scheduled_at": "{{ $json.publish_date }}"
}

Error Handling With the IF Node

The IF node after the API call checks {{ $json.success }}. On failure, the error branch sends a Slack message containing the post title and the error message. For 409 duplicate errors specifically, we route to a separate branch that logs the duplicate but does not alert — duplicates are expected when reprocessing a content batch.

Scheduling and Publishing Cadence

JekCMS supports three publishing modes through the API:

  • Immediate publish: omit the scheduled_at field — the post goes live instantly
  • Scheduled publish: pass an ISO 8601 timestamp (e.g., 2026-03-01T09:00:00+03:00) — JekCMS's cron publishes it at that time
  • Draft mode: use the /draft endpoint instead — the post is saved but not visible until manually published from the admin panel

For SEO purposes, we stagger publications at 90-minute intervals rather than publishing everything at once. The n8n Cron node triggers once per day, fetches all pending content items from a Google Sheet, and uses the Code node to assign sequential timestamps spaced 90 minutes apart starting from 09:00 in the site's timezone.

Category and Tag Automation

The API accepts category names as strings. If a category does not exist, JekCMS creates it automatically with a generated slug. Tags work the same way — pass an array of strings in the tags field. This means your n8n workflow does not need to know the site's existing category IDs; it can simply pass the category name from the content source and let JekCMS handle the lookup or creation.

Monitoring and Debugging

Every API request is logged to logs/api-{date}.log with the request method, endpoint, authentication result, response code, and execution time. For n8n debugging, enable the "Include Response Headers" option in the HTTP Request node — JekCMS returns an X-Request-ID header that maps to the server log entry. When filing a support request, include this ID for instant log lookup.

  • Average API response time for a text-only post: 180ms
  • Average response time with featured image URL fetch and AVIF conversion: 3.2 seconds
  • Maximum concurrent API requests supported per installation: 10 (configurable in config/api.php)
  • Rate limit: 120 requests per minute per API key (429 status code when exceeded)

Retry Strategy and Idempotency

Network failures are inevitable in any automated pipeline, so building a robust retry strategy is essential.

The JekCMS publish API is idempotent when the force_duplicate: false default is in effect: if n8n retries a failed request and the post was actually created on the first attempt, the API returns a 409 duplicate response instead of creating a second copy. This means you can safely enable n8n's built-in retry mechanism (Settings > Retry on Fail) with up to 3 attempts and a 30-second delay between retries without risking duplicate content.

For image-heavy workflows where the 3.2-second average response time can occasionally spike to 10 seconds or more on slow source servers, increase the HTTP Request node's timeout to 30 seconds and set the retry count to 2.

The combination of duplicate prevention at the API level and automatic retries at the workflow level means your content pipeline recovers from transient failures without manual intervention. Over our eight-month production run, this configuration reduced the effective failure rate from 0.3% to under 0.05%, with the remaining failures caused by permanently unreachable source URLs rather than transient network issues.