Automations

Blueprints that regenerate a fresh clip from one brief and publish it on a recurring schedule, plus their readiness checklist and stop reasons.

An automation is a blueprint: a video whose brief is reused to generate a fresh clip on a schedule, which is then published to a publishing profile. The blueprint itself is never published; it is the recipe.

BlueprintClip
Where it is listedGET /automationsGET /automations/{id}/clips
On GET /videosExcludedExcluded
FlagsisAutomation: trueisClip: true, parentVideoId points at the blueprint
CarriesThe schedule, the destination, the healthOne generation, one render, one publish

Create a blueprint

POST /automations takes the same brief as POST /videos, flagged as a blueprint, and queues its first generation. Send the brief flat or nested under brief; it must carry at least a prompt or a text script.

curl -X POST https://app.shortfast.com/api/v1/automations \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "One productivity tip for founders, different angle each time",
    "type": "faceless",
    "videoDuration": "short",
    "aspectRatio": "9:16",
    "voiceId": "Enceladus",
    "voiceProvider": "gemini"
  }'

A new blueprint has no schedule and no destination, so it starts paused with its whole checklist outstanding:

{
  "data": {
    "id": "aQ8vN2mK5tR9wL3xc",
    "title": "One productivity tip for founders",
    "status": "paused",
    "schedule": { "frequency": null, "timezone": "UTC", "times": [], "days": [] },
    "publishing": { "profileId": null, "platforms": [] },
    "autoRefill": false,
    "lastRunAt": null,
    "stopped": null,
    "health": {
      "ready": false,
      "blockers": [
        { "id": "no-schedule", "label": "Set a publishing schedule" },
        { "id": "no-profile", "label": "Choose where to publish" },
        { "id": "no-platforms", "label": "Select at least one platform" }
      ],
      "nextScheduledAt": null
    }
  }
}

An existing video can be promoted instead, with POST /videos/{id}/automation and { "enabled": true }. Promoting needs a video whose generation finished (warning-source-not-ready otherwise) and room under the plan's automation limit (warning-plan-automations). A clip cannot be promoted: promote the video it was made from, or the call is a 422. Sending { "enabled": false } turns a blueprint back into a plain video, pausing it first so the clips it had already armed are unscheduled.

The schedule

PATCH /automations/{id} updates any of schedule, profileId, platforms, autoRefill and status. Provide at least one. schedule carries the whole timing block, so send it complete rather than a partial edit.

frequencySlotsWhere the slots go
daily1times
twice-daily2times
thrice-daily3times
weekly1schedule
twice-weekly2schedule
thrice-weekly3schedule

A daily frequency needs exactly as many entries in times as it has slots; a weekly frequency needs the same count of day and time pairs in schedule. Setting one clears the other. timezone is an IANA name such as Europe/Paris and defaults to UTC.

Each slot has a time on a 24-hour clock and a mode: fixed posts at the stated time, random jitters the slot around it so a feed does not look machine-timed. mode defaults to fixed, and a bare "09:30" string is accepted in times and read as fixed.

curl -X PATCH https://app.shortfast.com/api/v1/automations/aQ8vN2mK5tR9wL3xc \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": {
      "frequency": "twice-daily",
      "timezone": "Europe/Paris",
      "times": [
        { "time": "09:30", "mode": "fixed" },
        { "time": "18:00", "mode": "random" }
      ]
    },
    "profileId": "pR4kM8xT2vQ6nL9wz",
    "platforms": ["tiktok", "youtube"],
    "autoRefill": true,
    "status": "active"
  }'

A weekly schedule sends pairs instead:

{
  "schedule": {
    "frequency": "twice-weekly",
    "timezone": "Europe/Paris",
    "schedule": [
      { "day": "tuesday", "time": "09:30", "mode": "fixed" },
      { "day": "thursday", "time": "18:00", "mode": "random" }
    ]
  }
}

The weekly pairs are written under schedule.schedule but read back under schedule.days. A round trip that posts the automation's own schedule object straight back therefore drops a weekly timing block: rebuild it from days before sending.

autoRefill decides whether the automation generates a fresh clip when its queue of armed clips runs dry, which is what keeps a schedule fed without a call from you.

Readiness and blockers

An automation only runs when three things are set. Anything missing is a blocker, and health.ready is false while any remain:

BlockerLabelFix
no-scheduleSet a publishing scheduleSend a schedule with a frequency and its slots
no-profileChoose where to publishSend a profileId from GET /profiles
no-platformsSelect at least one platformSend platforms from GET /platforms

Activating (status: "active") while any blocker stands is refused with 400 warning-publish-not-configured, and the message names them:

{
  "error": {
    "status": 400,
    "code": "warning-publish-not-configured",
    "message": "Finish setup first: Choose where to publish, Select at least one platform"
  }
}

GET /automations/{id}/health is the full picture, including counts the automation shape omits:

{
  "data": {
    "ready": false,
    "blockers": [{ "id": "no-platforms", "label": "Select at least one platform" }],
    "status": "paused",
    "autoRefill": true,
    "lastRunAt": "2026-08-05T18:00:12.000Z",
    "nextScheduledAt": null,
    "stopped": {
      "reason": "publish_no_accounts",
      "stoppedAt": "2026-08-05T18:01:44.000Z",
      "kind": "config",
      "label": "No account connected",
      "detail": "None of the selected platforms has a connected account. Connect one in Settings, then resume."
    },
    "clips": { "total": 12, "failed": 1 }
  }
}

nextScheduledAt is the earliest future clip slot, and null while the automation is paused or blocked. clips.failed counts clips whose generation, render or publish failed.

Stop reasons

An automation that cannot do its job is stopped automatically and stopped says why. kind is what decides your response: a config reason cannot clear on a retry and needs a fix from you, a transient one may clear on its own.

reasonkindWhat happened
publish_not_configuredconfigThe publishing destination went missing, so nothing can be posted
publish_authconfigThe connected social account rejected the post. Reconnect it in Settings, then resume
publish_no_accountsconfigNone of the selected platforms has a connected account
source_video_failedconfigThe blueprint could not be processed, so no new clips can be made from it
plan_downgradedconfigAutomations are not available on the current plan
consecutive_failurestransientSeveral clips in a row failed to generate or publish

Subscribe to automation.blocked to hear about a missing checklist item before it stops anything, and to automation.stopped for the stop itself. Fix the cause, then PATCH the automation back to status: "active".

Run one on demand

POST /automations/{id}/run produces one clip immediately, outside the schedule:

curl -X POST https://app.shortfast.com/api/v1/automations/aQ8vN2mK5tR9wL3xc/run \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 2b7d51e4-9f30-4c88-91a6-6f0b3d5c7e21"

Asynchronous: the response is the new clip with process.status: "QUEUED", and generating it charges credits like any other generation. The blueprint must be fully set up, or the call is refused with warning-publish-not-configured naming the blockers, exactly as activation is.

Listing and deleting

GET /automations lists the blueprints in the workspace, newest activity first, and accepts ?status=active or ?status=paused. paused is the implied default: a blueprint that was never activated carries no stored status at all.

DELETE /automations/{id} deletes the blueprint, every clip it produced and the files they own, and returns the storage to the workspace quota. It cannot be undone, and the response reports deletedClips and deletedBytes.

Reference

On this page