Examples
Practical, copy-paste flows for the Postally API. Every request uses the base URL https://app.postally.io/api/public/v1 and the two auth headers (Authorization + x-brand-id).
Upload media, then schedule a post
The most common flow: upload an image, then attach it to a scheduled post.
Node.js (fetch)
const BASE = "https://app.postally.io/api/public/v1";
const headers = {
Authorization: "Bearer pst_live_YOUR_API_KEY",
"x-brand-id": "YOUR_BRAND_ID",
};
// 1) Upload media
const form = new FormData();
form.append("file", await fetch("https://example.com/launch.png").then((r) => r.blob()), "launch.png");
const media = await fetch(`${BASE}/media/upload`, {
method: "POST",
headers, // do NOT set Content-Type; fetch sets the multipart boundary
body: form,
}).then((r) => r.json());
// 2) Schedule a post that uses it
const scheduled = await fetch(`${BASE}/posts`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
type: "schedule",
date: "2026-09-01T14:30:00Z",
shortLink: false,
posts: [
{
integration: { id: "YOUR_INTEGRATION_ID" },
value: [
{
content: "Big news drops today π",
image: [{ id: media.id, path: media.path }],
},
],
settings: { __type: "x" },
},
],
}),
}).then((r) => r.json());
console.log("Scheduled:", scheduled);Python (requests)
import requests
BASE = "https://app.postally.io/api/public/v1"
HEADERS = {
"Authorization": "Bearer pst_live_YOUR_API_KEY",
"x-brand-id": "YOUR_BRAND_ID",
}
# 1) Upload media
with open("launch.png", "rb") as f:
media = requests.post(
f"{BASE}/media/upload",
headers=HEADERS,
files={"file": f},
).json()
# 2) Schedule a post that uses it
payload = {
"type": "schedule",
"date": "2026-09-01T14:30:00Z",
"shortLink": False,
"posts": [
{
"integration": {"id": "YOUR_INTEGRATION_ID"},
"value": [
{
"content": "Big news drops today π",
"image": [{"id": media["id"], "path": media["path"]}],
}
],
"settings": {"__type": "x"},
}
],
}
res = requests.post(f"{BASE}/posts", headers={**HEADERS, "Content-Type": "application/json"}, json=payload)
print("Scheduled:", res.json())Publish to multiple platforms at once
Add one entry to posts[] per account. Here we publish immediately (type: "now") to X and LinkedIn in a single request β each with its own content and platform settings.__type.
curl -X POST https://app.postally.io/api/public/v1/posts \
-H "Authorization: Bearer pst_live_YOUR_API_KEY" \
-H "x-brand-id: YOUR_BRAND_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "now",
"date": "2026-09-01T00:00:00Z",
"shortLink": true,
"posts": [
{
"integration": { "id": "INTEGRATION_X" },
"value": [{ "content": "Shipping day! π https://acme.com/launch", "image": [] }],
"settings": { "__type": "x" }
},
{
"integration": { "id": "INTEGRATION_LINKEDIN" },
"value": [{ "content": "We just launched. Here is what changed and why it mattersβ¦", "image": [] }],
"settings": { "__type": "linkedin" }
}
]
}'Platform-specific settings
Some platforms require extra fields in settings. TikTok and YouTube are the most involved β here's the shape of each posts[] entry.
TikTok
{
"integration": { "id": "INTEGRATION_TIKTOK" },
"value": [{ "content": "Behind the scenes π¬", "image": [{ "id": "media_video_...", "path": "https://cdn.postally.io/media/clip.mp4" }] }],
"settings": {
"__type": "tiktok",
"privacy_level": "PUBLIC_TO_EVERYONE",
"duet": false,
"stitch": false,
"comment": true,
"autoAddMusic": "no",
"brand_content_toggle": false,
"brand_organic_toggle": false,
"content_posting_method": "DIRECT_POST"
}
}YouTube
{
"integration": { "id": "INTEGRATION_YOUTUBE" },
"value": [{ "content": "Full walkthrough of our new release.", "image": [{ "id": "media_video_...", "path": "https://cdn.postally.io/media/release.mp4" }] }],
"settings": {
"__type": "youtube",
"title": "Product release walkthrough",
"type": "public"
}
}Live OpenAPI reference
Every public endpoint is also available as an interactive OpenAPI/Swagger reference at https://app.postally.io/api/public/v1/docs. See the API Reference for the full field-by-field breakdown.