Content Scheduling
Deliver content library items on a schedule — daily rotation, weekly, random, or sequential.
Content schedules are reliable and recurring — Amba runs them on the cadence you configure, every tick lands a fresh delivery, and pausing or deleting a schedule keeps state consistent.
Schedule types
| Type | Default cron | What it does |
|---|---|---|
daily_rotation | 0 9 * * * | Rotates through items, one per day, at 09:00 in the chosen timezone |
weekly | 0 9 * * MON | Delivers one item per week on Mondays |
random | required | Picks a random item each tick |
sequential | required | Delivers items in sort_order order |
random and sequential require you to provide an explicit cron — the schedule type alone doesn't imply a cadence.
Create a schedule
Override the default cron with your own:
PATCH / DELETE
Updates apply atomically — if anything fails, the schedule reverts to its previous state so deliveries don't silently drift.
is_active: false pauses the schedule (no new deliveries fire) without deleting the row.
Deleting a schedule is also atomic — the recurring job is torn down first, then the row is removed.
Config keys
Each schedule gets a server-allocated config_key of the form content_<schedule_uuid>. This key is what the SDK sees on GET /client/content/today — it's stable across renames of the schedule's name.
config shape
Empty or missing cron for random / sequential returns 400 INVALID_SCHEDULE_CONFIG up front — the row never commits without a working schedule spec.
Overlap policy
If a previous content delivery is still running when the next tick arrives, the next tick is skipped rather than queued. This is the right default for content rotation; queueing would deliver two items simultaneously.
Life of a tick
Each tick:
- Loads the schedule + library.
- Picks the next item based on
schedule_type:daily_rotation/sequential: compute position from (count(deliveries)modcount(items)).random:ORDER BY random() LIMIT 1.
- Writes a row to
content_deliverieswith the chosen item id and timestamp. - The SDK's
getToday()readscontent_deliveriespluscontent_items.
SDK consumption
getToday() filters by occurred_at::date = CURRENT_DATE, so timezones matter — schedules default to UTC unless you set config.timezone.
MCP tools
| Tool | Description |
|---|---|
amba_create_content_schedule | Create a delivery schedule on a library |
Routes reference
| Method | Path | Description |
|---|---|---|
POST | /admin/content/schedules | Create schedule |
GET | /admin/content/schedules | List schedules for the project |
PATCH | /admin/content/schedules/:id | Update schedule atomically |
DELETE | /admin/content/schedules/:id | Tear down recurring delivery + row |
Database tables
| Table | Purpose |
|---|---|
content_schedules | Schedule definition + type, config |
content_deliveries | One row per tick: which item was delivered, at what time |
content_items | The items themselves, ordered by sort_order |
Next
- Content libraries — manage items and libraries.