CLIManaging posts

CLI

Managing posts

Create, schedule, list, edit and delete posts from the terminal: drafts, several networks, media, dry runs and a full JSON body.

Every post belongs to an establishment, so you pass its id with -e. Find it with sofia establishments:list (see accounts).

Publish a post

Without a date, the post goes out right away.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Tarte tatin du jour"

Schedule a post

Pass an ISO 8601 date with -s, --date.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Brunch ce samedi" -s 2026-11-07T09:00:00Z

Save a draft

--draft saves the post without publishing or scheduling it.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Brunch ce samedi" --draft

Several networks at once

List the networks separated by commas in -p, --platforms. Each one receives the same text.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram,facebook,linkedin -c "Tarte tatin du jour"

The media, format and account are shared too. These options shape the post:

  • -c, --content: the text of the post.
  • -f, --format: the format (post, reel, story, carousel…).
  • -a, --account: the connected account to publish from.

Add media

-m, --media takes media ids from your library or https addresses, separated by commas.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Tarte tatin du jour" \
  -m $MEDIA_ID,https://images.example.com/tarte-tatin.jpg

For an address, the type comes from the extension: video for mp4, mov, webm and m4v, image otherwise. To upload first, see media.

Dry run

--dry-run checks the post against each network’s rules and publishes nothing. See Dry run.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Tarte tatin du jour" --dry-run

Idempotency

Rerun a command safely with --idempotency-key: the same key gives the same post, never two. See Idempotency.

sofia posts:create -e $ESTABLISHMENT_ID -p instagram -c "Tarte tatin du jour" \
  --idempotency-key brunch-2026-11-07

Full body from a file

For per-network text, several media or a schedule in one go, write the whole body in a file and pass it with -j, --json. It replaces the content options.

{
  "establishmentId": "$ESTABLISHMENT_ID",
  "targets": [
    {
      "platform": "instagram",
      "text": "Tarte tatin du jour",
      "media": [{ "id": "$MEDIA_ID" }],
      "format": "post"
    },
    {
      "platform": "tiktok",
      "text": "Tarte tatin du jour",
      "media": [{ "url": "https://images.example.com/tarte-tatin.mp4", "type": "video" }]
    }
  ],
  "scheduledAt": "2026-11-07T09:00:00Z",
  "status": "scheduled"
}
sofia posts:create --json post.json

List posts

Filter the list with these options. The answer is paginated: see Pagination.

  • -e, --establishment: only this establishment.
  • --status: only posts in this status.
  • --from and --to: a date range.
  • --created-by me|app: posts you wrote yourself, or those created through the API.
  • --limit and --cursor: the page size and where to resume.
sofia posts:list -e $ESTABLISHMENT_ID --status scheduled --from 2026-11-01 --to 2026-11-30 --limit 20

Read, edit, delete

posts:update changes the date (-s), the status (draft or scheduled), or the whole body with -j.

sofia posts:get $POST_ID
sofia posts:update $POST_ID -s 2026-11-08T09:00:00Z
sofia posts:update $POST_ID --status draft
sofia posts:delete $POST_ID

Script with jq

Since the output is JSON, jq extracts what you need: ids, statuses, the cursor of the next page.

sofia posts:list -e $ESTABLISHMENT_ID --status scheduled | jq '.data[] | {id, status}'
sofia posts:list -e $ESTABLISHMENT_ID | jq -r '.nextCursor'

Next: accounts and media.

Was this page helpful?