Publishing
Set per-platform options with platformSpecificData, apply TikTok and Facebook settings to every entry at once, and know which value wins.
Most of a post is shared: the text, the media, the time. Some options only make sense on one platform, like a YouTube title, a Pinterest board or an Instagram collaborator. Those go in platformSpecificData on that platform's entry in platforms.
#Set an option on one platform
The shape of platformSpecificData depends on the entry's platform. Here the YouTube entry gets a title and a playlist, and the Pinterest entry gets a board and a link:
curl -X POST https://api.pozy.ai/v1/posts \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "How we cut our build times in half.",
"mediaItems": [{ "type": "video", "url": "https://pozy.ai/media/temp/1730289600_b5n8_builds.mp4" }],
"scheduledFor": "2026-11-06T16:00:00Z",
"platforms": [
{
"platform": "youtube",
"accountId": "6710c3e2a9f14b0d8e5c7a27",
"platformSpecificData": {
"title": "Halving our build times",
"visibility": "public",
"playlistId": "PLx8b2kq0Engineering",
"firstComment": "Chapters are in the description."
}
},
{
"platform": "pinterest",
"accountId": "6710c3e2a9f14b0d8e5c7a28",
"platformSpecificData": {
"boardId": "1093475830219481234",
"title": "Halving build times",
"link": "https://example.com/blog/build-times"
}
}
]
}'const res = await fetch("https://api.pozy.ai/v1/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "How we cut our build times in half.",
mediaItems: [{ type: "video", url: "https://pozy.ai/media/temp/1730289600_b5n8_builds.mp4" }],
scheduledFor: "2026-11-06T16:00:00Z",
platforms: [
{
platform: "youtube",
accountId: "6710c3e2a9f14b0d8e5c7a27",
platformSpecificData: {
title: "Halving our build times",
visibility: "public",
playlistId: "PLx8b2kq0Engineering",
firstComment: "Chapters are in the description.",
},
},
{
platform: "pinterest",
accountId: "6710c3e2a9f14b0d8e5c7a28",
platformSpecificData: {
boardId: "1093475830219481234",
title: "Halving build times",
link: "https://example.com/blog/build-times",
},
},
],
}),
});
if (!res.ok) throw new Error((await res.json()).error);requests.post(
"https://api.pozy.ai/v1/posts",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"content": "How we cut our build times in half.",
"mediaItems": [{"type": "video", "url": "https://pozy.ai/media/temp/1730289600_b5n8_builds.mp4"}],
"scheduledFor": "2026-11-06T16:00:00Z",
"platforms": [
{
"platform": "youtube",
"accountId": "6710c3e2a9f14b0d8e5c7a27",
"platformSpecificData": {
"title": "Halving our build times",
"visibility": "public",
"playlistId": "PLx8b2kq0Engineering",
"firstComment": "Chapters are in the description.",
},
},
{
"platform": "pinterest",
"accountId": "6710c3e2a9f14b0d8e5c7a28",
"platformSpecificData": {
"boardId": "1093475830219481234",
"title": "Halving build times",
"link": "https://example.com/blog/build-times",
},
},
],
},
timeout=30,
).raise_for_status()#The fields you will use most
This is a short list per platform. Each platform page documents every field, with limits and examples.
| Platform | Common platformSpecificData fields |
Full reference |
|---|---|---|
contentType (story), firstComment, collaborators, userTags, shareToFeed, reelCover, audioName, isPaidPartnership, locationId |
||
| TikTok | privacyLevel, allowComment, allowDuet, allowStitch, contentPreviewConfirmed, expressConsentGiven, commercialContentType, mediaType, videoCoverTimestampMs, draft |
TikTok |
| YouTube | title (100 chars), visibility, madeForKids, categoryId, playlistId, firstComment, containsSyntheticMedia, notifySubscribers |
YouTube |
contentType (story, reel), title, firstComment, pageId, geoRestriction, facebookSettings |
||
firstComment, documentTitle, organizationUrn, disableLinkPreview, poll, reshareUrl, audience, geoRestriction |
||
X (twitter) |
threadItems, replyToTweetId, quoteTweetId, replySettings, poll, longVideo, article, madeWithAi, paidPartnership |
X |
| Threads | threadItems, topic_tag (50 chars), firstComment (500 chars) |
Threads |
boardId, boardSectionId, title (100 chars), link, coverImageUrl, isAiGenerated |
||
| Bluesky | threadItems, langs |
Bluesky |
| Google Business Profile | topicType (STANDARD, EVENT, OFFER), callToAction, event, offer, locationId, languageCode |
Google Business Profile |
| Snapchat | contentType (story, saved_story, spotlight) |
Snapchat |
| Telegram | parseMode, disableWebPagePreview, disableNotification, protectContent |
Telegram |
| Discord | channelId (required), embeds, poll, crosspost, forumThreadName, forumAppliedTags |
Discord |
| Slack | threadTs, unfurlLinks, unfurlMedia, username, iconUrl |
Slack |
subreddit, title, url, flairId, nsfw, spoiler |
Reddit (publishing paused) |
geoRestriction (Facebook, LinkedIn, X) takes { "countries": ["ES", "PT"] }, up to 25 two-letter country codes, and limits who can see the post.
#Settings for every TikTok or Facebook entry
TikTok and Facebook settings can also go at the top level of the body, as tiktokSettings and facebookSettings. They are copied into every entry of that platform, which saves repeating them when you post to several TikTok accounts at once:
{
"platforms": [
{ "platform": "tiktok", "accountId": "6710c3e2a9f14b0d8e5c7a24" },
{ "platform": "tiktok", "accountId": "6710c3e2a9f14b0d8e5c7a29", "platformSpecificData": { "privacyLevel": "MUTUAL_FOLLOW_FRIENDS" } }
],
"tiktokSettings": {
"privacyLevel": "PUBLIC_TO_EVERYONE",
"allowComment": true,
"allowDuet": false,
"allowStitch": false,
"contentPreviewConfirmed": true,
"expressConsentGiven": true
}
}The merge is key by key and the entry wins. In the example, the second account keeps MUTUAL_FOLLOW_FRIENDS and takes every other key from tiktokSettings.
TikTok only publishes when contentPreviewConfirmed and expressConsentGiven are true and privacyLevel is one of the values the account allows. None of the three has a default. Your app must show TikTok's preview and consent step to the person posting before you set them.
On Facebook, draft, carouselCards, carouselLink and textFormatPresetId live inside facebookSettings. Every other Facebook field sits directly on platformSpecificData.
#Rules that decide which value wins
| Situation | What happens |
|---|---|
customContent, customMedia or scheduledFor on an entry |
Replaces the top-level content, mediaItems or scheduledFor for that entry only. |
tiktokSettings or facebookSettings at the top level |
Merged into each matching entry. Keys set on the entry are kept. |
A field on the wrong entry, or platformSpecificData at the top level |
Ignored. The post is still saved, and the response lists what was ignored in warnings. |
PUT /v1/posts/{postId} with a settings object |
The object you send replaces the stored one whole. Send every key you want to keep. Settings objects you leave out are kept as they were. |
A misplaced option never fails the request, so it is easy to miss. Log warnings from every create and update while you build your integration.
#When a value is rejected
A value the platform cannot accept fails the whole request with 400 and nothing is created. param gives the exact path of the bad field:
{
"error": "title must be at most 100 characters",
"type": "invalid_request_error",
"code": "invalid_field_value",
"param": "platforms[0].platformSpecificData.title"
}Run the same body through POST /v1/tools/validate/post to catch these before you create anything (Validation).
#Endpoints
| Endpoint | What it does |
|---|---|
POST /v1/posts |
Create post |
PUT /v1/posts/{postId} |
Update post |
POST /v1/tools/validate/post |
Validate post content |