Publishing
Connect a rendered video to a publishing profile, pick platforms, and read the publish state including which platforms had no account.
Publishing sends a rendered video to the social accounts a user connected in the ShortFast app. Two things decide where it goes: a profile (a named destination holding the connected accounts) and a list of platforms.
Profiles and accounts
A profile is created and connected in the app, not through the API. GET /profiles lists the ones this workspace holds, each with the accounts connected
to it. It is unpaginated: a workspace holds a handful at most.
curl https://app.shortfast.com/api/v1/profiles \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": [
{
"id": "pR4kM8xT2vQ6nL9wz",
"name": "Acme brand",
"description": "Main brand accounts",
"color": "#0A66C2",
"isDefault": true,
"createdAt": "2026-05-14T08:31:00.000Z",
"accounts": [
{ "id": "acc_tt_01", "platform": "tiktok", "username": "acmehq", "displayName": "Acme", "pictureUrl": "https://cdn.shortfast.com/uploads/avatars/acmehq.jpg" },
{ "id": "acc_yt_01", "platform": "youtube", "username": "@acme", "displayName": "Acme Studio", "pictureUrl": null }
]
}
]
}accounts is cached. Pass ?refresh=true (or ?refresh=1) on /profiles or
/profiles/{id} to re-read them upstream first. That is slower, and it never
fails the request: if the accounts cannot be re-read, the cached ones are
returned unchanged. Use it before a publish that depends on an account the user
just connected.
Platforms
GET /platforms returns the platform keys a profile can publish to. These are
exactly the values platforms accepts on a publish and on an
automation's destination. The list is static and
workspace-independent, so read it once at integration time rather than per call.
| Key | Name |
|---|---|
tiktok | TikTok |
youtube | YouTube |
instagram | |
twitter | Twitter/X |
facebook | |
linkedin | |
threads | Threads |
pinterest | |
reddit | |
bluesky | Bluesky |
A platform key is not a promise that an account exists for it. Whether a profile can actually reach a platform is decided per publish, from the accounts connected to that profile.
Check before publishing
GET /videos/{id}/publish answers three questions at once: can this video be
published, where would a publish send it, and what happened last time.
curl https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/publish \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": {
"videoId": "7bQxL2mF9dR4tK1sv",
"rendered": true,
"destination": { "profileId": "pR4kM8xT2vQ6nL9wz", "platforms": ["tiktok", "youtube"] },
"publish": null
}
}rendered is true once a render exists; a video can only be published with
one. destination is what a publish with no explicit body would use: a clip
inherits its blueprint's destination, so an automation's clips need no
configuration of their own. publish is null until the first attempt.
Publish a video
curl -X POST https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/publish \
-H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9a1c4d77-52b6-4e0f-8c33-71d0e2f9b845" \
-d '{
"profileId": "pR4kM8xT2vQ6nL9wz",
"platforms": ["tiktok", "youtube"],
"caption": "Burnout is not a workload problem. #founders"
}'Every field is optional. Omit profileId and platforms to use the video's own
destination, and caption to use the video's brief.description (caption is
capped at 5000 characters, comfortably above every platform's own limit).
Duplicate platform keys are collapsed, and an unknown one is a 400 before
anything is sent.
Always send an Idempotency-Key. A publish is the one action with a visible,
irreversible side effect on someone else's timeline, and a retry after a client
timeout would post the same video twice.
missingPlatforms
A requested platform with no connected account does not fail the call. It is reported back instead, so the platforms that could be reached still go out:
{
"data": {
"videoId": "7bQxL2mF9dR4tK1sv",
"platforms": ["tiktok"],
"missingPlatforms": ["youtube"],
"publish": {
"status": "COMPLETED",
"scheduledAt": null,
"startedAt": "2026-08-06T09:40:02.000Z",
"publishedAt": "2026-08-06T09:40:31.000Z",
"failedAt": null,
"platforms": ["tiktok"],
"missingPlatforms": ["youtube"],
"caption": "Burnout is not a workload problem. #founders",
"error": null
}
}
}platforms is what the video actually reached and missingPlatforms what it did
not. Treat a non-empty missingPlatforms as a partial success worth surfacing:
the publish is COMPLETED and will not retry those platforms on its own. The
only case that fails outright is none of the requested platforms resolving, which
is warning-publish-no-accounts.
The publish state machine
publish.status moves through four values, and the timestamps say when each
transition happened:
| Status | Meaning | Timestamp |
|---|---|---|
SCHEDULED | An automation slotted this clip to go out later | scheduledAt |
PUBLISHING | The post is in flight | startedAt |
COMPLETED | The video is live on platforms | publishedAt |
FAILED | The attempt stopped. error.code says why | failedAt |
DELETE /videos/{id}/publish wipes the block so the video can be sent again. It
is refused with warning-invalid-input while a publish is live or already
finished: clearing it then would lose the result and let an automation post the
same video twice.
When a publish is refused
| Code | Why | What clears it |
|---|---|---|
warning-plan-publish | Publishing needs a paid plan. Downloads stay free | Upgrade |
warning-publish-not-configured | No render yet, no profile selected, no platforms selected, or the profile no longer exists | Fix the destination |
warning-publish-no-accounts | None of the requested platforms has a connected account | Connect an account |
warning-publish-auth | A connected account's authorization expired | Reconnect it in Settings |
The same codes come back on publish.error.code when an attempt fails after it
started, and on the video.publish_failed webhook. Subscribe to
video.published and video.publish_failed rather than polling: a publish
triggered by an automation happens without any call from you.