CLI
Install the PublishQ CLI to schedule posts, upload media, and read your connected accounts from a shell, a CI job, or an AI agent with terminal access.
Publish and schedule posts from the terminal, and manage the accounts, media and workspaces behind them, without opening a browser. The same command runs in your shell, in a CI job, or in an agent that has terminal access.
Output is JSON by default, which is what makes it a good fit for an agent. Pass --pretty when you want to read it yourself.
Install
npm install -g @publishq/cli@latestYou get two commands, publishq and pq. They are the same binary.
Sign in
pq loginIt prints a link and a code, and opens the link if the machine has a browser. Check that the page shows the same code, click Approve, and the CLI saves the login to ~/.publishq/config.json, where it renews itself. On a server over SSH, open the link on any other device. pq logout signs out.
An agent that runs one command at a time should use pq login --no-wait: it prints the link and the code and exits, the agent passes them to you, and running pq login again after you approve finishes the sign-in.
You can see and disconnect every login under Connected apps. To use an API key instead, create one under API Keys and run pq auth set --key "pq_live_...".
In CI, skip the config file
Set PUBLISHQ_API_KEY in the environment instead and the CLI reads it directly, so there is nothing to write to disk and nothing to clean up afterwards. PUBLISHQ_API_URL points it at another server.
Posts
pq posts # list (the default command)
pq posts list --page 1 --limit 20
pq posts get <post-id>
# Draft: no schedule and no --publish-now
pq posts create --content "Hello" --account <account-id>
# Scheduled
pq posts create --content "Hello" --account <id> --scheduled-at 2026-08-01T09:00:00Z
# Immediate, to several accounts, with media
pq posts create --content "Hello" \
--account <id> --account <id2> \
--media-id <media-id> --publish-now
pq posts update <post-id> --content "New text"
pq posts update <post-id> --accounts-json '[{"accountId":"<id>","platformSpecificSettings":{"thumbnailMediaId":"<image-media-id>"}}]'
pq posts update <post-id> --accounts-json '[{"accountId":"<id>","platformSpecificSettings":{"thumbnailMediaId":null}}]'
pq posts delete <post-id>
pq posts remove-account <post-id> <account-id>Repeat --account and --media-id to target several accounts or attach several files.
Per-account overrides
--account covers the simple case. When one account needs its own text or platform settings, use --accounts-json instead. The two cannot be combined.
pq posts create --content "Default text for everyone else" \
--accounts-json '[
{
"accountId": "<tiktok-account-id>",
"postOverrides": { "content": "TikTok caption" },
"platformSpecificSettings": {
"privacyLevel": "PUBLIC_TO_EVERYONE",
"disableComment": false,
"disableDuet": false,
"disableStitch": false,
"brandContentToggle": false,
"brandOrganicToggle": false
}
}
]' --publish-nowFor TikTok, call pq accounts tiktok-creator-info <account-id> first: it returns the privacy levels that account is actually allowed to use.
Accounts
pq accounts list
pq accounts list --platform TIKTOK --platform BLUESKY # OR filter
pq accounts list --workspace-id <workspace-id>
pq accounts tiktok-creator-info <account-id>Media
pq media list [--page 1] [--limit 20] [--media-type IMAGE]
pq media get <media-id>
pq media upload --file ./photo.jpg
pq media delete <media-id>Upload returns a media object; pass its id to pq posts create --media-id <id>. Files up to 4 GB are accepted (500 MB on the Free plan). Delete removes the file from the library and from storage. A file still attached to a draft or scheduled post is refused with 409 until that post is published or deleted.
Media folders
pq media folders
pq media list --folder "Channel A" [--include-subfolders]
pq media upload --file ./clip.mp4 --folder "Channel A/Shorts"
pq media move <media-id> [<media-id>...] --folder "Channel A/Shorts"
pq media move <media-id> --top-level
pq media folders rename "Channel A/Shorts" Reels
pq media folders preview-delete "Channel A"
pq media folders delete "Channel A" --expected-file-count 12--folder "" on media list lists the files at the top level. folders delete deletes every file in the folder and its subfolders, except files a draft or scheduled post uses; pass the fileCount from preview-delete, and nothing is deleted if the folder changed since. See Media folders.
Workspaces
pq workspaces list
pq workspaces get <workspace-id>
pq workspaces create --name "Client A"Scopes
API keys carry scopes, and a call missing one returns 403.
| Scope | Commands |
|---|---|
posts:read | posts list, posts get |
posts:write | posts create, posts update, posts delete, posts remove-account |
accounts:read | accounts list, accounts tiktok-creator-info |
workspaces:read | workspaces list, workspaces get |
workspaces:write | workspaces create |
media:read | media list, media get, media folders, media folders preview-delete |
media:write | media upload, media delete, media move, media folders rename, media folders delete |
Related
- Post to social media from the command line
- MCP Server for agents that speak MCP
- SDK for building your own