Publishing and scheduling
A rendered video can go out two ways: POST /posts publishes to one platform right now; POST /posts/schedule queues one or more platforms for a future time. Both are free. Supported platforms: youtube, tiktok, instagram, x, facebook, linkedin, threads.
Publishing requires a connected account for the platform. Connecting accounts (OAuth) happens in the dashboard, not over the API.
Who can you post as? (GET /accounts, scope accounts:read)
curl -s https://faceless.so/api/v1/accounts \
-H "Authorization: Bearer $FACELESS_API_KEY"
{
"success": true,
"data": { "youtube": [{ "id": "665f1b2a9c31a2b3c4d5ee01", "channelName": "Deep Sea Facts" }], "tiktok": [], "instagram": [] }
}
Use an account's id as authId in POST /posts when the team has several accounts on one platform, and as destinationAccounts in series.
Publish now (POST /posts, scope posts:write)
The video must be rendered first (renderedVideoUrl present; see videos). One platform per call:
curl -s -X POST https://faceless.so/api/v1/posts \
-H "Authorization: Bearer $FACELESS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"videoId": "665f1b2a9c31a2b3c4d5e801", "platform": "youtube", "title": "The ocean has rivers underwater"}'
{
"success": true,
"data": { "platform": "youtube", "videoId": "665f1b2a9c31a2b3c4d5e801", "postUrl": "https://youtube.com/shorts/dQw4w9WgXcQ" }
}
title and description are optional; when omitted the video's stored post metadata is used. privacyStatus (public, unlisted, private) applies to YouTube only. Rate limit: 10 per 300s.
Schedule for later: metadata first, then schedule
Scheduling posts to multiple platforms at once, at a future time, and renders the video first if needed. It validates that every platform in the list already has its post metadata stored on the video, so the flow is always two steps.
1. Set per-platform metadata (PATCH /videos/{id}, scope videos:write)
curl -s -X PATCH https://faceless.so/api/v1/videos/665f1b2a9c31a2b3c4d5e801 \
-H "Authorization: Bearer $FACELESS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"youtubePost": {"title": "The ocean has rivers underwater", "privacyStatus": "public"},
"tiktokPost": {"title": "underwater rivers are real #ocean"}
}'
The blocks per platform: youtubePost (title max 100, optional description, privacyStatus), tiktokPost (title), instagramPost (caption), xPost (text max 280), facebookPost (description), linkedinPost (description), threadsPost (text max 500).
2. Schedule (POST /posts/schedule, scope posts:write)
curl -s -X POST https://faceless.so/api/v1/posts/schedule \
-H "Authorization: Bearer $FACELESS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"videoId": "665f1b2a9c31a2b3c4d5e801", "platforms": ["youtube", "tiktok"], "scheduledTime": "2026-08-01T18:00:00Z"}'
scheduledTime is ISO 8601 and must be in the future. A platform without its metadata block set is rejected with invalid_input; set it in step 1 and retry. Rate limit: 20 per 300s.
Cancel (DELETE /posts/{id}, scope posts:write)
The id is the video id you scheduled. Cancels the pending scheduled posting; posts that already went out are unaffected. Cancelling something no longer scheduled returns 409 conflict.
curl -s -X DELETE https://faceless.so/api/v1/posts/665f1b2a9c31a2b3c4d5e801 \
-H "Authorization: Bearer $FACELESS_API_KEY"
See what is queued (GET /calendar, scope posts:read)
Scheduled, posted and failed posts across all platforms in a date range. Check it before scheduling more:
curl -s "https://faceless.so/api/v1/calendar?startDate=2026-08-01&endDate=2026-08-31&platform=youtube" \
-H "Authorization: Bearer $FACELESS_API_KEY"
Optional filters: platform and status (scheduled, posted, failed).
With the CLI
faceless posts publish --video-id <videoId> --platform youtube --json
faceless videos update <videoId> --youtube-title "..." --tiktok-title "..."
faceless posts schedule --video-id <videoId> --platforms youtube,tiktok --scheduled-time "2026-08-01T18:00:00Z" --json
faceless posts cancel <videoId>
faceless calendar --start-date 2026-08-01 --end-date 2026-08-31 --json