Content Calendar

Recurring posts

Use cron-based recurring schedules to generate content slots automatically.

A recurring schedule is a cron pattern that generates new content slots on a regular cadence. Rather than creating every post by hand, you define a template and let the engine fill your calendar.

How it works

  1. You create a recurring schedule with a cron expression, a caption template, and target accounts
  2. A Durable Object computes the next occurrence from the cron and arms an alarm
  3. When the alarm fires, the engine creates a new content slot from the template
  4. The slot is placed in draft (for you to customize) or scheduled (fire-and-forget) depending on your autoSchedule setting
  5. The DO immediately computes the next occurrence and re-arms — the loop continues until you deactivate the schedule

Creating a recurring schedule

POST /content/recurring
Content-Type: application/json
 
{
  "name": "Weekly tip",
  "cronExpression": "0 9 * * 1",
  "timezone": "Asia/Kolkata",
  "templateCaption": "💡 Tip of the week: [your tip here]",
  "templateMediaIds": [],
  "targetConnectionIds": ["conn_twitter_abc123", "conn_linkedin_xyz789"],
  "autoSchedule": false
}
Field Required Description
name Yes Display name for the schedule
cronExpression Yes Standard 5-field cron (min hour day month dow)
timezone Yes IANA timezone for cron evaluation
templateCaption Yes Caption for generated slots
templateMediaIds No Array of media IDs to attach to each generated slot
targetConnectionIds Yes Accounts to publish to
autoSchedule No false (default) — generated slots are drafts; true — slots are scheduled immediately

Cron expression format

5-field standard cron. The timezone you specify is used when computing occurrence times.

Expression Meaning
0 9 * * 1 Every Monday at 09:00
0 9 * * 1,3,5 Monday, Wednesday, Friday at 09:00
0 9,17 * * * Every day at 09:00 and 17:00
0 9 1 * * First of every month at 09:00
0 9 * * 0 Every Sunday at 09:00

Note: Seconds are not supported (5-field only). The engine uses the cron-parser library for evaluation.

Auto-schedule vs draft

Setting Generated slot status Use when
autoSchedule: false draft You want to customize each slot's caption before it goes live
autoSchedule: true scheduled Template is final and posts should go live without review

With autoSchedule: true, every slot fires at the cron time with exactly the template caption. With autoSchedule: false, you get a draft in your calendar that you can edit and then schedule manually (or submit for approval).

Updating a schedule

PATCH /content/recurring/:scheduleId
Content-Type: application/json
 
{
  "cronExpression": "0 10 * * 1",
  "autoSchedule": true
}

Updating the cron expression recalculates the next occurrence and re-arms the Durable Object alarm. The change takes effect from the next fire — already-generated slots are not affected.

Deactivating a schedule

PATCH /content/recurring/:scheduleId
Content-Type: application/json
 
{ "isActive": false }

Or delete it entirely:

DELETE /content/recurring/:scheduleId

Deactivating sets isActive = false and cancels the DO alarm. The schedule record is kept (with generated history). Deleting removes the record and cancels the alarm.

What happens at generation time

When the recurring DO alarm fires:

  1. A new content slot is created with source: "recurring" and a reference back to the recurring schedule ID
  2. If autoSchedule: true: a SlotScheduler DO is armed immediately for the slot's scheduled time
  3. The next cron occurrence is calculated and the recurring DO re-arms
  4. A duplicate guard prevents the same slot from being generated twice: if the alarm fires within 30 seconds of a prior generation, the second fire is ignored

Limitations

  • Caption templates are plain text — no per-occurrence variables (e.g., auto-incrementing week numbers) are supported. Content is always the same template text.
  • Media is fixed at schedule-definition time. Changing templateMediaIds on the schedule does not affect already-generated slots.
  • One schedule generates one slot per occurrence, targeting all targetConnectionIds — there is no per-platform rotation.
Content Engine · Content CalendarEdit on GitHub