Scheduling
Drafts, exact times, queue slots, dry runs, recurrence, and the post lifecycle.
POST /posts supports three scheduling modes, selected by which fields you
send:
| You send | You get |
|---|---|
| neither field | A draft; nothing is scheduled |
scheduled_at | A post scheduled for that exact ISO 8601 UTC time |
use_next_slot: true | A post queued into the next open posting-schedule slot |
use_next_slot takes precedence: when it is true, scheduled_at is ignored.
If no slot is open it returns 422 NO_SLOT_AVAILABLE. You can preview the
slot first with GET /posts/{post_id}/publishes/next_slot, which returns the
earliest open slot for the post's accounts.
Posting schedules themselves (the weekly slot grid) are managed per channel:
read them with GET /posting_schedules (schedules:read) and update with
schedules:write.
Dry runs
Add dry_run: true to POST /posts or POST /posts/bulk to run every
validation (accounts, content, character limits, scheduled_at, tier gates)
and get the would-be post back without persisting anything. The response
carries dry_run: true. Dry runs are free: use them to validate before
anything goes live.
Publishing an existing post
POST /posts/{post_id}/publishes (publish:write) publishes a post that
already exists. Without scheduled_at or use_next_slot it is sent
immediately. Target accounts default to those already attached to the post;
override with social_account_id(s). A scheduled_at here must be more than
30 seconds in the future.
Post lifecycle
A post's status moves through:
draft → scheduled → processing → postedThe full set: draft, needs_review, approved, scheduled, processing,
posted, failed, partial_failure, upload_pending. Review states apply
when approval workflows are in use (needs_review → approve or reject).
partial_failure means some target platforms published and some failed; the
per-platform outcome is on each entry of post_accounts
(platform_status, platform_error, and a permalink once live).
Flexible posts
flexible: true allows the scheduler to shift the post to the nearest open
slot rather than holding its exact time.
Recurrence
Recurring posts require a paid plan. Set recurrence_frequency (daily,
weekly, or monthly) with recurrence_interval, recurrence_weekdays
(for weekly), recurrence_monthday (for monthly), and an optional
repeat_until. With recurrence_jitter_enabled: true, each occurrence is
shifted by up to ±15 minutes instead of posting at the exact anchor time.
Evergreen recycling
evergreen: true marks a post for evergreen recycling: once it performs, it
is re-queued into open slots after a fixed per-platform cooldown. Requires a
paid plan (403 TIER_UPGRADE_REQUIRED otherwise). Supply up to 5
evergreen_variations (pre-approved rewrites, max 2,000 characters each) and
recycles cycle through them instead of AI-rewriting at publish time.
Bulk creation
POST /posts/bulk accepts up to 50 posts. Each item is created in its own
transaction, so one invalid item does not roll back the others: the response
lists created and per-index errors, returning 201 if any item succeeded
and 422 if all failed.