1
Create the post
pending_review. Nothing is public yet — it shows up in
the studio’s review queue like any other post.channels defaults to that creator’s connected channels, so most calls need only
account_id, asset_ids and caption. The format (photo, carousel or video) is
derived from the media and validated against every target platform before the post is
written — a carousel that a platform cannot take is a 400, not a failed publish an
hour later. Pass format to declare it yourself instead.hashtags are bare words, without the #. They are appended to the caption when the
post is sent, and they count against each platform’s caption limit.2
Send it
3
Watch it land
Post settings
Everything the studio’s composer can set is available at creation. All of it is optional; each setting is applied only on the platform it belongs to.Per-platform overrides
platform_settings takes caption and scheduled_for on every channel, plus title and
visibility (public / unlisted / private) on YouTube. A caption set here replaces
the shared one on that channel only; a scheduled_for here replaces the shared time.
Two rules keep mistakes loud rather than silent: every key must name a channel the post
actually targets, and an unrecognised setting is a 400 rather than a value quietly
dropped on the way to the platform.
Saving as a draft
"draft": true hands the post to TikTok’s Creator Inbox instead of publishing it. The
creator finishes and posts it from the TikTok app. The post reaches draft_sent, never
published — there is no publish time to report, because the creator may never post it.
This is orthogonal to timing: a draft can still be sent now, scheduled or queued.
The mode decides when you hand it over, draft decides what you hand over.
Posting from the creator’s phone
"physical_device": true sends the post from a real phone bound to that creator, a
device that runs the account the way a person would, instead of going through a platform’s
publishing API. Everything else about the call is unchanged: the post is still created at
pending_review, and POST /v1/clips/{id}/publish is still what hands it over.
Two things have to be true, and both are resolved server-side rather than taken from the
request:
- Your workspace has phone posting enabled. It is off by default and turned on per workspace. Ask support to enable it.
- The creator is bound to a device. Binding happens in the studio, per creator.
400 on physical_device saying which one, never a silently dropped
destination.
The phone is a destination like any channel, so it can run alongside them:
physical_device plus an explicit
empty channel list:
channels still means “every connected
channel”, so leaving it out would post to those as well.
The post reads back "physical_device": true, and once the phone has accepted the
hand-off it also carries device_post_id.
The review gate
The states a post moves through:- A post enters at
pending_review. The API cannot create one in any other state. scheduledis reachable only frompending_review. Asking to publish an already published post is a400that says so.publishedis written only after the platform confirms. If the hand-off fails, the post staysscheduledwith the reason recorded, and you can retry — it is never falsely marked live.
Want a human in the loop? Create posts and never call publish. They queue up in the
studio’s review screen, where an operator approves them exactly as they would a post
the platform generated. The API gives you the operator’s authority; it does not force
you to use it.
Requirements
The creator needs a connected channel
The creator needs a connected channel
Channels are connected in the studio, per creator. A creator with none gets a
400
telling you so — the API cannot connect accounts on your behalf.The one exception is a device-only post: "physical_device": true with an explicit
"channels": [] needs no connected channel, because the phone is the destination.Media has to be finished
Media has to be finished
Use asset ids from a
succeeded generation, or from a completed upload. An asset that
is still uploading is rejected.Ten assets maximum
Ten assets maximum
One video, or up to ten stills for a carousel. Platform-specific carousel limits are
checked at creation.
From the CLI
crl posts create alone leaves the post in review. --publish now|schedule|queue chains
the second call. Publishing from a terminal asks for confirmation; pass --yes in
scripts.
The settings above have flags too:
--format, --timezone and --draft map to the fields of the same name. The rest of
platform_settings (per-platform captions and times) goes through
--platform-settings '{"TikTok":{"caption":"…"}}'.