ChirpieDocs
CLI

CLI Commands

Complete reference for all Chirpie CLI commands.

Posts

Create a Post

chirpie post "Your post text here"
FlagDescription
-a, --account <id>Account ID (auto-selects if you have one account). Repeat it to publish the same post to several accounts at once
--config <json-or-file>Per-account overrides for a multi-account post, as JSON or a path to a JSON file. Keyed by account ID, each value taking text, media, first_comment and configuration, which is where the options a placement carries go (collaborators, user_tags, cover, video_cover_timestamp_ms, share_to_feed, trial_reel on Instagram, link on a Facebook Page). See Post to several accounts at once
-m, --media <files...>Image or video files on this machine, or public URLs. Files are uploaded first. Up to 4 on most platforms (JPEG, PNG, WebP, GIF up to 5MB; MP4/MOV up to 512MB)
--alt <text...>Describe each item for people using a screen reader, in the same order as --media
--first-comment <text>Post this as a comment under the post, as soon as it goes out. X, Threads, Instagram and Facebook only. It counts as one post against your monthly quota
--instagram-placement <placement>Where the post goes on Instagram: feed (the default), story or reel. A story takes exactly one image or video, no caption (pass "" as the text) and no first comment. A reel takes exactly one video. See Instagram publishing options
--facebook-placement <placement>Where the post goes on a Facebook Page: feed (the default) or story. A story takes exactly one image or video, no text and no first comment. See Facebook publishing options
-s, --schedule <datetime>Schedule for a future time. An ISO 8601 timestamp carrying a timezone (2026-04-01T14:00:00Z, 2026-04-01T16:00:00+02:00), or a local time with no offset (2026-11-01T09:30) read in --timezone or the timezone saved on your account
--timezone <iana>The IANA timezone a --schedule with no offset is read in, such as America/New_York. Daylight saving is worked out for the date you name. See Timezones
--idempotency-key <key>Make a retry safe. The same key with the same request replays the first answer instead of sending it again, for 24 hours. One is generated per invocation when you do not pass one. See Idempotency
--draftSave without publishing. Nothing is sent, nothing counts against your quota, and anything that would go wrong is printed back
--jsonOutput as JSON
# Schedule a post
chirpie post "Launching tomorrow!" -s "2026-04-01T14:00:00Z"

# Save a draft to finish later
chirpie post "Half an idea" --draft

# Post with an image
chirpie post "Check this out!" -m https://example.com/screenshot.png

# Post to a specific account
chirpie post "Hello!" -a 550e8400-e29b-41d4-a716-446655440000

# Post to several accounts in one call
chirpie post "Hello everywhere!" -a ACCOUNT_A -a ACCOUNT_B

# Give one account its own text
chirpie post "Hello everywhere!" -a ACCOUNT_A -a ACCOUNT_B \
  --config '{"ACCOUNT_B":{"text":"Hello, longer version for this one."}}'

Put the link in the first comment:

chirpie post "We rebuilt scheduling this week." \
  --first-comment "Full write-up: https://example.com/blog/scheduling"

A multi-account post prints one line per account, and the call reports a failure for any account the platform refused while the others stay published. See Post to several accounts at once.

Create a Thread

chirpie thread "First post" "Second post" "Third post"
FlagDescription
-a, --account <id>Account ID. Repeat it to publish the thread to several accounts at once
--config <json-or-file>Per-account overrides, as JSON or a path to a JSON file. Each value takes posts, which replaces the whole thread for that account, plus first_comment and configuration. A thread publishes to the feed, so an Instagram story or reel, and a Facebook Page story, are refused: each is a single post
--first-comment <text>Post this as a comment under the thread's last post, as soon as it goes out. X, Threads, Instagram and Facebook only. It counts as one post against your monthly quota
-s, --schedule <datetime>Schedule the thread. An ISO 8601 timestamp carrying a timezone, or a local time with no offset read in --timezone or the timezone saved on your account
--timezone <iana>The IANA timezone a --schedule with no offset is read in, such as America/New_York. See Timezones
--idempotency-key <key>Make a retry safe. One is generated per invocation when you do not pass one. See Idempotency
--draftSave without publishing. A draft thread may be a single post while you are still writing it
--jsonOutput as JSON

Minimum 2 posts, maximum 25, or 1 to 25 with --draft.

A thread is atomic: if any part fails, every part that had already published is deleted from the platform and the whole thread's quota is refunded. In the rare case a part could not be removed, the CLI prints it under "Still live on the platform, delete these yourself" with its link, and the error code is thread_rollback_incomplete rather than upstream_error, because retrying would publish it twice.

# The same thread to two accounts, with a longer version for the second
chirpie thread "First post" "Second post" -a ACCOUNT_A -a ACCOUNT_B \
  --config '{"ACCOUNT_B":{"posts":[{"text":"a"},{"text":"b"},{"text":"c"}]}}'

List Posts

chirpie posts
FlagDescription
--status <status>Filter by status: draft, scheduled, publishing, published, failed, deleted
--account <id>Filter by account
--group <id>Show every post of one multi-account send, by its group ID
--limit <n>Number of results (default 20)
--include-hiddenInclude posts you have hidden. Off by default on every filter
--jsonOutput as JSON

A post you deleted stays in the listing, with status deleted: a delete takes the post down from the platform and never removes your record of it.

Get Post Details

chirpie posts get <post_id>
FlagDescription
--jsonOutput as JSON

Update a Post

Edit a post that has not published yet, or finish a draft.

chirpie posts update <post_id> --text "Now with the typo fixed"
chirpie posts update <post_id> --schedule-at 2027-04-02T09:00:00Z
FlagDescription
-t, --text <text>Replacement post text
-m, --media <files...>Replacement image or video files on this machine, or public URLs
--alt <text...>Replacement alt text, in the same order as --media
--clear-mediaRemove the media from the post
--first-comment <text>A new first comment, replacing the one the post carries. Pass "" to remove it. This is also how a first comment is added to a post that has not published yet
--instagram-placement <placement>Move the post to another Instagram placement: feed, story or reel. The media is checked again against it. This replaces the whole block, so a queued reel loses its collaborators, cover and trial-reel setting unless you send them again
--facebook-placement <placement>Move the post to another Facebook Page placement: feed or story. This replaces the whole block, as above
--clear-placementPut the post back to a plain feed post, dropping every publishing option it carries
-s, --schedule-at <datetime>New publish time. An ISO 8601 timestamp carrying a timezone, or a local time with no offset read in --timezone or the timezone saved on your account. Omit it to keep the time the post already has. On a draft it queues the post, unless --keep-draft is passed too
--timezone <iana>The IANA timezone a --schedule-at with no offset is read in, such as America/New_York
--keep-draftKeep a draft a draft, so --schedule-at only changes the time it remembers. Valid on its own as well
--jsonOutput as JSON

Only a post that has not gone out can be edited. Rescheduling one post of a thread moves every part of it.

Publish a Draft

chirpie posts publish <post_id>
chirpie posts publish <post_id> --text "The final wording"
FlagDescription
-t, --text <text>Final post text, saved before publishing
--jsonOutput as JSON

Every rule and the monthly quota apply at this point, so a draft that would be refused stays a draft, unchanged. A draft thread publishes whole.

Delete a Post

chirpie posts delete <post_id>
FlagDescription
--jsonOutput as JSON (includes cancelled_ids when a queued post is cancelled, and deleted_ids when a draft is deleted)

On a published post, delete takes it down from the platform and succeeds only once the platform confirms it is gone. Nothing reaches a platform for a post that has not gone out: a queued one is cancelled and its quota returned, and a draft is simply marked deleted, since a draft never counted against anything. Chirpie keeps the post in every case, marked deleted, so it stays in your history and in chirpie posts --status deleted. A published TikTok post, a Facebook Page story, or a post on an Instagram account connected through Instagram rather than via Facebook, cannot be deleted, so it is refused with delete_unsupported: delete it in the platform's own app, and hide it here if you do not want to see it. See the delete table.

Retry a First Comment

Post a first comment that failed, again. It re-sends the text the post already carries. That text cannot be changed once the post is out, so set it while the post is still a draft or still queued with chirpie posts update <post_id> --first-comment "..." instead.

chirpie posts first-comment <post_id>
FlagDescription
--idempotency-key <key>Make a retry safe. The same key replays the first answer instead of sending the comment again, for 24 hours
--jsonOutput as JSON (the post, with its first comment now posted)

A first comment never fails its post, so a published post can be carrying one that did not go out. A retry that works counts as one post against your monthly quota, exactly as the first attempt would have.

Hide a Post

chirpie posts hide <post_id>
chirpie posts unhide <post_id>
FlagDescription
--jsonOutput as JSON (includes hidden_ids, every post that moved)

Hiding takes a post out of your Chirpie listings and nothing else. Nothing reaches the platform: the post stays exactly as it is, keeps its analytics and its comments, and unhide puts it back. A thread, or a multi-account send, is hidden as the one thing it was made as.

Hiding a queued post does not stop it publishing: the scheduler pays no attention to it. Use chirpie posts delete to stop a scheduled post going out.

List them again with chirpie posts --include-hidden.

Drafts

A draft is saved and nothing else: nothing reaches the platform and nothing counts against your quota until you promote it. Saving one prints, one per line, anything that would go wrong if it were sent as it stands.

# Save it
chirpie post "Half an idea" --draft

# See what is saved
chirpie posts --status draft

# Change the time it remembers, still a draft
chirpie posts update <post_id> --schedule-at 2027-04-02T09:00:00Z --keep-draft

# Queue it
chirpie posts update <post_id> --schedule-at 2027-04-02T09:00:00Z

# Or send it now
chirpie posts publish <post_id>

Comments

List Comments on a Post

chirpie comments list <post_id>
FlagDescription
--limit <n>Comments to show (default 25, max 100)
--cursor <cursor>The next_cursor from the previous page
--since <datetime>Only comments posted after this ISO 8601 time
--no-syncShow the stored comments without refreshing from the platform
--include-hiddenInclude comments you have hidden
--include-deletedInclude deleted comments, with the last text Chirpie stored for them
--jsonOutput as JSON

The table shows a short comment ID, the author, the time, the comment text, its state (hidden or deleted, blank for a live comment), and a tick under replied for a comment you have already answered. The author is the display name, falling back to the handle; your own replies show the connected account's name. A deleted comment keeps its text. When the stored comments could not be refreshed, the reason is printed above the table.

Reply to a Comment

chirpie comments reply <post_id> <comment_id> --text "Yes, that works."
FlagDescription
--text <text>The reply (required)
--idempotency-key <key>Make a retry safe. The same key with the same reply replays the first answer instead of sending it again, for 24 hours
--jsonOutput as JSON

A reply is published to the platform like any other post, so it counts as one post against your monthly quota.

Hide a Comment

chirpie comments hide <post_id> <comment_id>
chirpie comments hide <post_id> <comment_id> --unhide
FlagDescription
--unhideShow a comment you hid earlier
--jsonOutput as JSON

Facebook, Instagram and Threads support hiding. Everywhere else the command reports that the platform has no hide rather than pretending it worked.

Delete a Comment

chirpie comments delete <post_id> <comment_id>
FlagDescription
-y, --yesSkip the confirmation prompt
--jsonOutput as JSON

On Facebook and Instagram you can delete any comment on a post you published. Everywhere else you can delete only replies you wrote. On Facebook, Instagram, Threads and LinkedIn the replies under a deleted comment are deleted with it; see what happens to the replies.

A delete cannot be undone, so it asks first. In a script or any other non-interactive shell there is nobody to ask, so pass -y or the command stops without deleting anything.

The post and comment IDs can be the short ones the tables show, or the full ones from --json. See IDs.


Accounts

List Accounts

chirpie accounts

Shows a table of all connected accounts with platform, username, display name, scheduled post count, and active status.

Inactive accounts are listed too, with a ✗ under active. An account marked over plan limit is connected but not publishing because your plan's account limit was already full when it was connected. Activate it below, or upgrade.

Activate or Deactivate an Account

chirpie accounts activate <id>
chirpie accounts deactivate <id>
FlagDescription
--jsonOutput as JSON (deactivate includes canceled_posts)

Use the short account ID chirpie accounts shows, or the full one from chirpie accounts --json. --json may go before or after the account ID: chirpie accounts deactivate <id> --json and chirpie accounts --json deactivate <id> are equivalent.

Chirpie never discards a connected account when your plan runs out of room. One Facebook authorization can grant several Pages at once; Chirpie stores every Page and switches on as many as your plan allows, leaving the rest inactive. These two commands choose which ones publish. Deactivating keeps the account connected and frees a plan slot, so you can activate a different one without reauthorizing.

Deactivating cancels the account's scheduled posts. A deactivated account cannot publish, so its whole queue is cancelled and returned to your monthly quota. The command prints how many. The scheduled column in chirpie accounts shows the number in advance. Activating the account again does not bring them back.

# Park one Page and switch on another
chirpie accounts deactivate 550e8400-e29b-41d4-a716-446655440000
chirpie accounts activate 7c9e6679-7425-40de-944b-e07fc1f90ae7

# Read the result from a script
chirpie accounts deactivate 550e8400-e29b-41d4-a716-446655440000 --json | jq '.canceled_posts'

Activating past your plan's account limit fails with a plan-limit error.

Disconnect an Account

chirpie accounts disconnect <id>
FlagDescription
-y, --yesSkip the confirmation prompt
--jsonOutput as JSON (includes canceled_posts)

Ends the connection. The account stops publishing immediately and stops counting against your plan's account limit, and Chirpie lets go of the credential it stored for it.

A disconnect cannot be undone, so it asks first. In a script or any other non-interactive shell there is nobody to ask, so pass -y or the command stops without disconnecting anything.

Disconnecting cancels the account's scheduled posts. Every post still queued against it is cancelled and returned to your monthly quota. The command prints how many, and the scheduled column in chirpie accounts shows the number in advance. Connecting the account again does not bring them back.

# Ask first, then disconnect
chirpie accounts disconnect 550e8400-e29b-41d4-a716-446655440000

# From a script
chirpie accounts disconnect 550e8400-e29b-41d4-a716-446655440000 -y --json | jq '.canceled_posts'

Disconnect when you are done with the account. Deactivate instead when you mean to switch it on again: deactivating keeps the stored credential, so activating needs no reauthorization, while connecting a disconnected account again means authorizing it on the platform again. Posts the account already published are kept either way.

Connect an X Account

chirpie accounts connect-x

Prints an authorization URL. Open it in your browser to complete the X OAuth flow.

Every connect-* command accepts --json, which prints the raw result instead of the human-readable line.

Connect a Bluesky Account

chirpie accounts connect-bluesky --handle <handle> --app-password <password>
FlagDescription
--handle <handle>Your Bluesky handle. The first part alone is enough (yourname), and yourname.bsky.social, a handle on your own domain, or the email on your account also work.
--app-password <password>A Bluesky app password, shaped xxxx-xxxx-xxxx-xxxx. Create one in Bluesky under Settings, Privacy and Security, App Passwords. Omit the flag to be prompted for it without echo.
--jsonOutput as JSON
# Example
chirpie accounts connect-bluesky --handle mybot --app-password xxxx-xxxx-xxxx-xxxx

Anything not shaped like an app password, your account password included, is refused before any request is made, with bluesky_app_password_required and the same message the API gives. The value is never printed.

Connect a LinkedIn Account

chirpie accounts connect-linkedin
chirpie accounts connect-linkedin --pages   # the LinkedIn Pages you administer (coming soon)

Prints an authorization URL. Open it in your browser to complete the LinkedIn OAuth flow.

Connect a Threads Account

chirpie accounts connect-threads

Prints an authorization URL. Open it in your browser to complete the Meta OAuth flow for Threads.

Connect a Mastodon Account

chirpie accounts connect-mastodon --instance <instance>
FlagDescription
--instance <instance>Your Mastodon server, handle or profile URL: mastodon.social, @you@mastodon.social and https://mastodon.social/@you all work. Only the server is kept.
--jsonOutput as JSON
# Examples: all three connect you on mastodon.social
chirpie accounts connect-mastodon --instance mastodon.social
chirpie accounts connect-mastodon --instance @you@mastodon.social
chirpie accounts connect-mastodon --instance https://mastodon.social/@you

A value naming no server is refused before any request with mastodon_instance_invalid.

Prints an authorization URL. Open it in your browser to complete the Mastodon OAuth flow.

Connect an Instagram Account

chirpie accounts connect-instagram
chirpie accounts connect-instagram --via facebook
chirpie accounts connect-instagram --via facebook --reconnect
FlagDescription
--via <route>How to connect: instagram (the default) signs in with Instagram, facebook signs in with Facebook and connects the Instagram accounts linked to the Pages you share. Any other value is refused
--reconnectOn --via facebook, ask Facebook again about anything that was turned down last time
--jsonOutput as JSON

Prints an authorization URL. Open it in your browser to finish the flow.

Both routes need an Instagram professional account (Business or Creator), and both publish, thread, schedule and report analytics identically. They differ in one way: on an account connected with --via facebook, chirpie posts delete <id> really takes a published post down, and on an account connected the default way it is refused with delete_unsupported. --via facebook also needs the Instagram account to be linked to a Facebook Page, and one run can connect several accounts at once, one per linked Page; anything past your plan's account limit is stored inactive (shown as over plan limit) rather than dropped, so use chirpie accounts activate <id> to pick.

Connecting an account you already have through the other route moves it rather than adding a second one: it keeps its id and everything it has published, and only what it can do changes, so going to --via facebook adds deleting and coming back takes it away again. Where the two routes report different Instagram accounts you get a second account instead, so run chirpie accounts afterwards to see what you have. See switching between the two routes.

Connect a Facebook Page

chirpie accounts connect-facebook
chirpie accounts connect-facebook --reconnect

Prints an authorization URL. Open it in your browser to complete the Facebook OAuth flow. You choose which Pages to grant.

Use --reconnect when the account has authorized Facebook before, so Facebook asks again about anything that was turned down last time.

If the flow finishes and no Page was imported, Facebook did not share one. Run it again and, in the Facebook window, choose Edit settings, tick every Page you want Chirpie to post to, and leave Show a list of the Pages you manage and Create and manage content on your Page turned on. Pages already connected stay connected while you retry.

Every granted Page is imported as its own account. If you grant more Pages than your plan's account limit allows, Chirpie switches on as many as it can and stores the rest inactive (shown as over plan limit in chirpie accounts), so nothing is dropped. Use chirpie accounts activate <id> to pick which Pages publish. Running this command again re-runs the import, so Pages added later are picked up without disconnecting anything.

Connect a Telegram Bot

chirpie accounts connect-telegram --bot-token <token> --chat-id <id>
FlagDescription
--bot-token <token>Telegram bot token from @BotFather (prompts securely if omitted)
--chat-id <id>Channel or group. A bare name is enough (channelname), and @channelname, a https://t.me/channelname link, or the numeric ID also work (prompts if omitted).
--jsonOutput as JSON

More Platforms

Pinterest, TikTok, YouTube, and Google Business Profile are coming soon.

Use Your Own X Developer App

Connect X accounts through your own X app so posts use your X API credits. See Bring your own X keys for the full walkthrough.

# Set or replace your keys (prompts for the secret if --client-secret is omitted)
chirpie accounts x-keys set --client-id "YOUR_CLIENT_ID" --label "Acme social app"

# Check whether your own app is configured
chirpie accounts x-keys status

# Remove your keys
chirpie accounts x-keys remove
FlagDescription
--client-id <id>OAuth 2.0 Client ID from developer.x.com (required for set)
--client-secret <secret>OAuth 2.0 Client Secret (prompts securely if omitted)
--label <label>Optional name for the app
--jsonOutput raw JSON

After setting keys, run chirpie accounts connect-x to move an account onto your app. Accounts you don't reconnect keep using whichever app connected them.


API Keys

List Keys

chirpie keys
FlagDescription
--jsonOutput as JSON

Create a Key

chirpie keys create
chirpie keys create -n "My Bot Key"

# A narrower key: repeat --scope once per permission
chirpie keys create -n "Publishing bot" --scope posts:write --scope media:write
FlagDescription
-n, --name <name>Key name
--scope <scope>What the new key may do. Repeat it once per scope. Omit it for a key that can do exactly what the key you are calling with can do. See Scopes
--jsonOutput as JSON

Allowed scopes: posts:read, posts:write, accounts:read, accounts:write, analytics:read, comments:read, comments:write, media:write, keys:write.

A key can never grant a scope it does not itself hold. chirpie keys prints each key's scopes, or all for a key with full access.

Revoke a Key

chirpie keys revoke <key_id>
FlagDescription
--jsonOutput as JSON

Analytics

Get Post Metrics

chirpie analytics <post_id>
chirpie analytics <post_id> --refresh
FlagDescription
--refreshAsk the platform for the current numbers instead of reading the stored snapshot. Allowed once per post every 5 minutes; past that it reports analytics_refresh_rate_limited and the stored numbers are still one ordinary call away
--jsonOutput as JSON

Displays engagement metrics for a post. Available metrics vary by platform:

  • X: impressions, likes, retweets, replies, quotes, bookmarks, and clicks
  • Bluesky: likes, reposts, replies, and quotes
  • LinkedIn: likes, comments, and shares
  • Threads: views, likes, replies, reposts, and quotes
  • Mastodon: favourites, reblogs, and replies
  • Instagram: views, likes, comments, shares, and saves
  • Facebook: views, reactions, comments, shares, and clicks
  • Telegram: No analytics available

On this page