Upload-Post CLI
The official command line for Upload-Post. Publish, schedule and track posts on TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Google Business, Discord, Telegram and more, from your terminal, your scripts or an AI agent.
npx @upload-post/cli post video -p my-brand --platforms tiktok,instagram,youtube \
-m ./clip.mp4 -t "Launch day" --wait
It is built on the official upload-post SDK and only uses endpoints documented at docs.upload-post.com.
Install
# run it without installing
npx @upload-post/cli --help
# or install the `upload-post` command globally
npm install -g @upload-post/cli
upload-post --help
Requires Node.js 18 or newer.
Authentication
Get an API key at app.upload-post.com/api-keys, then:
upload-post login # asks for the key, checks it, saves it
upload-post whoami # which account and plan the key belongs to
login stores the key in ~/.config/upload-post/config.json (or $XDG_CONFIG_HOME/upload-post/config.json), readable only by you (mode 600). It can also read the key from stdin: echo "$KEY" | upload-post login.
The key is looked up in this order, first match wins:
--api-key <key>- the
UPLOAD_POST_API_KEYenvironment variable - the saved config file
upload-post logout deletes the saved key.
Commands
| Command | What it does |
|---|---|
login / logout | Save or remove your API key |
whoami | Account email and plan behind the key |
profiles [username] | Your profiles and the accounts connected to each (and which need reconnecting) |
post video|photos|text|document | Publish now, schedule, or add to the queue |
status <request_id|job_id> | Per-platform result of an upload |
scheduled | Scheduled and queued posts that have not run yet |
cancel <job_id> | Cancel a scheduled/queued post (its credits are refunded) |
history | Past uploads, one row per platform |
analytics <profile> | Followers, reach, views... per platform |
comments list|reply | Read and answer comments (Instagram, Facebook, YouTube, LinkedIn, TikTok, X, Threads, Bluesky) |
dms list|send | Instagram direct messages |
Every command has --help with examples, e.g. upload-post post video --help.
Publishing
# Video to several platforms, wait for the result
upload-post post video -p my-brand --platforms tiktok,instagram,youtube \
-m ./clip.mp4 -t "Launch day" -d "Longer description for YouTube/LinkedIn" --wait
# Photo carousel (local files and URLs can be mixed)
upload-post post photos -p my-brand --platforms instagram,threads \
-m ./1.jpg ./2.jpg https://cdn.example.com/3.jpg -t "Behind the scenes"
# Text post, scheduled in a timezone
upload-post post text -p my-brand --platforms x,linkedin,threads -t "We just shipped" \
--schedule 2026-10-01T09:00:00 --timezone Europe/Madrid
# Next free slot of the profile's queue
upload-post post text -p my-brand --platforms linkedin -t "Weekly tip" --queue
# LinkedIn document (PDF, PPT, PPTX, DOC, DOCX)
upload-post post document -p my-brand -m ./deck.pdf -t "Q3 results"
Common options:
| Option | Meaning |
|---|---|
-p, --profile <name> | Profile to publish from (or UPLOAD_POST_PROFILE) |
--platforms <list> | Comma-separated, e.g. tiktok,instagram,x. X is x |
-t, --title <text> | Title / caption. For text posts, the text itself |
-d, --description <text> | Longer text used by LinkedIn, Facebook, YouTube and Pinterest |
-m, --media <paths or URLs> | The video, photos or document |
--schedule <ISO 8601> | Publish later (up to 365 days ahead) |
--timezone <IANA> | Timezone for --schedule; UTC by default |
--queue | Add to the next free queue slot |
--first-comment <text> | First comment after publishing |
-o, --option key=value | Any platform-specific API field (repeatable, see below) |
--idempotency-key <key> | Sending the same key again within 24 h never publishes twice |
-w, --wait | Block until every platform has a final result |
--timeout <seconds> | Limit for --wait (default 900) |
--dry-run | Print the exact request, send nothing |
Reddit is temporarily unavailable in Upload-Post (the API answers 503 reddit_unavailable), so the CLI refuses it up front.
Platform-specific options
Everything platform-specific goes through --option, with the API field name exactly as written in the docs (video, photos, text, document). Repeat it for several fields; repeat a [] field for arrays. Prefix a value with @ to send a local file.
upload-post post video -p my-brand --platforms tiktok,youtube,instagram -m ./clip.mp4 -t "Demo" \
--option privacy_level=SELF_ONLY \
--option privacyStatus=unlisted \
--option tags[]=demo --option tags[]=launch \
--option media_type=REELS \
--option tiktok_title="Short caption for TikTok" \
--option thumbnail=@./thumb.jpg
Field names are taken as-is, so they follow the docs even where they are camelCase (YouTube's privacyStatus, categoryId...). Check what will be sent with --dry-run before publishing.
Tracking
upload-post status 1a2b3c4d5e # request_id from an upload
upload-post status 1a2b3c4d5e --wait # keep polling until it is final
upload-post scheduled -p my-brand
upload-post cancel a1b2c3d4e5f6
upload-post history --limit 20 --status failed
Uploads run asynchronously. Without --wait, post returns as soon as Upload-Post accepts the post and prints its request_id. Scheduled and queued posts return a job_id instead.
Analytics, comments, DMs
upload-post analytics my-brand # every connected platform
upload-post analytics my-brand --platforms instagram,tiktok --json
upload-post comments list -p my-brand --platform youtube --post-id dQw4w9WgXcQ
upload-post comments reply -p my-brand --platform instagram --comment-id 1789 --message "Thanks!"
upload-post comments reply -p my-brand --platform instagram --comment-id 1789 --message "Check your DMs" --private
upload-post dms list -p my-brand
upload-post dms send -p my-brand --recipient-id 17841400123456789 --message "Hi!"
For AI agents
The CLI is designed to be driven by agents such as Claude Code, Codex or Cursor, as well as by CI jobs.
-
Always pass
--json. stdout then carries exactly one JSON document, for success and for errors alike. Progress messages go to stderr. -
Pass
--waitwhen you publish, so the command returns only when every platform has a final result, with the post URLs:upload-post post video -p my-brand --platforms tiktok,instagram -m ./clip.mp4 -t "Hi" --wait --json{
"success": true,
"request_id": "1a2b3c4d5e",
"job_id": null,
"upload": { "success": true, "request_id": "1a2b3c4d5e", "total_platforms": 2 },
"status": {
"status": "completed",
"completed": 2,
"total": 2,
"results": [
{ "platform": "tiktok", "success": true, "post_url": "https://www.tiktok.com/@brand/video/..." },
{ "platform": "instagram", "success": true, "post_url": "https://www.instagram.com/reel/..." }
]
}
} -
Branch on the exit code, not on text:
Code Meaning 0 Success 1 The API returned an error, or could not be reached 2 Invalid command line (unknown flag, missing option, bad value) 3 No API key, or the key was rejected (HTTP 401) 4 The post finished but at least one platform failed 5 --waittimed out; the upload keeps running, check it withstatus -
Errors keep the API's own
message, plus the HTTP status and the full response:{ "success": false, "error": { "message": "Invalid API key", "code": "http_401", "exit_code": 3, "status": 401, "response": { "success": false, "message": "Invalid API key" } } } -
Retrying is safe with
--idempotency-key. If a publish times out, rerun it with the same key instead of posting twice. -
Use
--dry-runto show a user exactly what will be published before doing it. -
Authenticate with
UPLOAD_POST_API_KEYin the environment rather than--api-key, so the key does not end up in shell history or logs. SetUPLOAD_POST_PROFILEto skip--profile. -
Start with
upload-post profiles --jsonto find profile names and the platforms connected to each. An account withreauth_required: truehas to be reconnected in the dashboard before it can publish.
Environment variables
| Variable | Purpose |
|---|---|
UPLOAD_POST_API_KEY | API key |
UPLOAD_POST_PROFILE | Default profile for post, comments and dms |
UPLOAD_POST_BASE_URL | API base URL (default https://api.upload-post.com/api) |
XDG_CONFIG_HOME | Where the config directory lives (default ~/.config) |
Links
- npm: @upload-post/cli
- Source: github.com/Upload-Post/upload-post-cli