PublishQPublishQ

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@latest

You get two commands, publishq and pq. They are the same binary.

Sign in

pq login

It 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-now

For 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.

ScopeCommands
posts:readposts list, posts get
posts:writeposts create, posts update, posts delete, posts remove-account
accounts:readaccounts list, accounts tiktok-creator-info
workspaces:readworkspaces list, workspaces get
workspaces:writeworkspaces create
media:readmedia list, media get, media folders, media folders preview-delete
media:writemedia upload, media delete, media move, media folders rename, media folders delete

On this page