Create posts
On this page
POST /v1/scheduled_posts creates one post per channel you list, all with the same content, scheduled for
the same time. You get back every post's ID and its full record.
You need: an API key and the IDs of the channels to post to
(GET /v1/channels).
Schedule a post
curl -X POST https://public-api.robopost.app/v1/scheduled_posts \
-H "Authorization: Bearer $ROBOPOST_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: launch-2026-11-20-facebook-linkedin" \
-d '{
"text": "We just launched! https://example.com/launch",
"channel_ids": ["<facebook channel id>", "<linkedin channel id>"],
"image_object_ids": ["<media id>"],
"schedule_at": "2026-11-20T15:00:00Z"
}'The response holds one entry per channel:
{
"scheduled_posts": [ { "id": "8c1f…", "channel_ids": ["<facebook channel id>"], "…": "…" } ],
"posts": [
{
"id": "8c1f…",
"revision": 2,
"status": "scheduled",
"channel_id": "<facebook channel id>",
"social_network": "FACEBOOK",
"schedule_at": "2026-11-20T15:00:00.000Z",
"media": { "ready": true, "image_object_ids": ["<media id>"], "…": "…" },
"…": "…"
}
]
}posts is the full record described in List and read posts; keep each
id to follow the post. scheduled_posts is the older, shorter shape, kept for existing integrations.
Tip
always send an Idempotency-Key. If the connection drops before you get the answer, send the
same request again with the same key: you get the original result instead of duplicate posts. See
Idempotency.
Add media
Use media from the team's library, or let Robopost download it from a public URL:
| Field | What to send |
|---|---|
image_object_ids |
IDs returned by media upload or found in the media library |
video_object_id |
One video ID |
gif_object_id |
One GIF ID |
image_urls, video_url, gif_url |
Public URLs pointing straight at the file |
With URLs, posts start in status preparing_media while Robopost downloads the files, then move to
scheduled. If a download fails, the post becomes failed with code MEDIA_DOWNLOAD_FAILED and the
reason; it is never silently dropped. Media IDs from another team are refused with MEDIA_NOT_FOUND.
Set network options
Each network has its own optional settings object. Send only the ones you need:
{
"text": "Behind the scenes",
"channel_ids": ["<youtube channel id>", "<tiktok channel id>"],
"video_object_id": "<video id>",
"schedule_at": "2026-11-20T19:00:00Z",
"youtube_settings": { "videoTitle": "Behind the scenes", "videoType": "short", "videoPrivacyStatus": "public" },
"tiktok_settings": { "title": "Behind the scenes", "privacyLevel": "PUBLIC_TO_EVERYONE" },
"first_comment": "Full video on our channel",
"made_with_ai": false
}| Object | Common fields |
|---|---|
youtube_settings |
videoTitle, videoDescription, videoType (video or short), videoPrivacyStatus, selfDeclaredMadeForKids |
tiktok_settings |
title, privacyLevel, disableComment, disableDuet, disableStitch, autoAddMusic |
instagram_settings |
postType, locationId |
facebook_settings |
postType |
pinterest_settings |
pinTitle, destinationLink |
wordpress_settings |
postTitle, postText, postSlug, postType, postCategories, postTags |
gmb_settings |
postTopicType, offer and event fields |
The OpenAPI description (/openapi.json) lists every field and its allowed values. first_comment posts a
comment under the post right after it publishes, on networks that support it. made_with_ai sets the
network's AI label where the network allows apps to (TikTok and X).
Post now, draft or collection
- Publish as soon as possible: set
schedule_atto the current time or earlier. - Draft:
"is_draft": true. One draft is created for all the channels listed; it isn't published. A single-channel draft can be scheduled later withPATCH. - Collection post:
"post_collection_id": "<id>"adds the post to an evergreen collection instead of scheduling it.
Repeat a post
{ "is_recur": true, "recur_interval": "WEEKLY", "recur_until_dt_enabled": true, "recur_until_dt": "2027-03-01T00:00:00Z" }recur_interval is one of EVERY_3_HOURS, EVERY_6_HOURS, BI_DAILY, DAILY, WEEKLY, MONTHLY,
DAILY_SPECIFIC_TIME_SLOTS (with daily_recur_interval_time_slots, for example ["09:00", "18:00"]) or
WEEKLY_SPECIFIC_TIME_SLOTS (with weekly_recur_interval_time_slots). Each repetition is a new post.
When creation is refused
| Status and code | Fix |
|---|---|
400 CHANNEL_NOT_FOUND |
The channel ID isn't one of this team's live channels |
400 CHANNEL_IDS_REQUIRED |
List at least one channel, or set is_draft |
400 MEDIA_NOT_FOUND |
A media ID isn't in this team's library |
409 PLAN_LIMIT_HIT |
The plan's scheduled-post limit is reached |
409 ACCOUNT_USAGE_FROZEN |
The subscription isn't active |
422 |
The body doesn't match the schema; detail says which field |