# CLI Account Management Commands

Configuration, media library, folders, and webhook management.

## Setup and configuration

| Command | Description |
|---------|-------------|
| `setup` | Interactive setup: prompts for an API key, validates it, writes the config file, and adds `.omnisocials/` to `.gitignore`. Flags: `--api-key <key>` (skip the prompt), `--global` (write the global config), `--base-url <url>` |
| `config:show` | Show the resolved config: masked API key, base URL, and which source it came from |

These two commands are the only ones that run without authentication. See
[CLI authentication](/cli#authentication) for the full resolution order.

## Media

| Command | Description |
|---------|-------------|
| `media:list` | List uploaded media files. Flags: `--limit`, `--offset` |
| `media:upload` | Upload from a URL (image, video, or PDF). Flags: `--url` (required), `--filename`, `--name`, `--folder`, `--folder-id`, `--pdf-mode`. PDFs are split into one image slide per page for carousels; `--pdf-mode document` keeps the PDF as one media item whose single id expands into every page |
| `media:upload-base64` | Upload a local file: `--file <path>` (auto-encodes and infers the MIME type) or `--data <base64>` plus `--mime-type <type>`; also `--filename`, `--name`, `--folder`, `--folder-id`, `--pdf-mode` |
| `media:check` | Check media compatibility against target platforms before posting. Pass `--url`, `--media-id`, or `--size-bytes` plus `--mime`. For a library image (`--media-id`) it also prints how each channel shows it as a feed post (ratio, whether it fits, the crop target and the default action), so you can decide on `--media-fit` before you post |
| `media:delete <id>` | Delete a media file |

```bash
# Upload a local video and verify it works everywhere you want to post
omnisocials media:upload-base64 --file ./reel.mp4
omnisocials media:check --media-id 12345
```

## Folders

| Command | Description |
|---------|-------------|
| `folders:list` | List media folders with id, name, parent, and item count |
| `folders:create` | Create a folder. Flags: `--name` (required), `--parent-id` (nested folders) |

## Hashtag sets

Save a group of hashtags once, then apply it to any post with `posts:create --hashtag-set "<name>"`. Tags merge into the captions at create time (editing a set later never changes existing posts), duplicates already in a caption are skipped, and Instagram's 30-hashtag cap fails fast. Add `--hashtag-placement first_comment` to post the tags as the automatic first comment where supported, and `--hashtag-platforms instagram,tiktok` to target a subset of channels.

| Command | Description |
|---------|-------------|
| `hashtag-sets:list` | List saved sets with id, name, tag count, and a preview |
| `hashtag-sets:create` | Save a set. Flags: `--name` (required, unique per workspace), `--tags` (required, e.g. `"#fitness #gym"`; the `#` is optional, max 100 tags) |
| `hashtag-sets:update <id>` | Rename or replace tags. Flags: `--name`, `--tags` (replaces the full list) |
| `hashtag-sets:delete <id>` | Delete a set. Posts that already used it keep their hashtags |

```bash
omnisocials hashtag-sets:create --name "Fitness Brand" --tags "#fitness #gym #workout"
omnisocials posts:create --text "New PB today" \
  --channels instagram,tiktok \
  --hashtag-set "Fitness Brand" --hashtag-placement first_comment
```

## Automations (comment to DM)

An automation DMs a person once when they comment a keyword on an Instagram post (or send it in a DM or a story reply), and can post a public reply under the comment. The API key needs the opt-in `automations:read` and `automations:write` scopes (Settings, API, "Automations" on the key).

| Command | Description |
|---------|-------------|
| `automations:list` | List automations with status, trigger, keywords, post and counts. Flags: `--status <active\|paused\|completed>`, `--post-id` |
| `automations:get <id>` | One automation in full |
| `automations:create` | Flags: `--dm "<text>"` (required), `--keywords "guide,link"`, `--match <word\|contains\|any>`, `--reply "Sent you a DM!"` (public reply, comma list for variations), `--post-id <id>` or `--instagram-media-id <id>`, `--scope <post\|next_post\|any>`, `--triggers comment,dm,story_reply`, `--max-sends <n>`, `--stop-at <ISO8601>`, `--name`, `--paused` |
| `automations:update <id>` | Same flags, all optional, plus `--pause` / `--resume` |
| `automations:delete <id>` | Delete it and its activity. DMs already sent stay sent |
| `automations:events <id>` | The activity: who commented or wrote, what was sent, skips with their reason. Flags: `--outcome <sent\|skipped\|failed\|pending>`, `--limit`, `--offset` |

A new post can carry its automation: `posts:create --dm-keywords "guide" --dm-message "Here is the guide" --dm-reply "Sent you a DM!"` (Instagram must be a channel); `posts:update <id> --no-dm` removes it.

```bash
omnisocials automations:create --post-id 83778183 \
  --keywords "guide,link" --dm "Here is the guide: https://example.com/guide" \
  --reply "Sent you a DM!,Check your inbox" --max-sends 500
omnisocials automations:events 100000004 --outcome sent
```

## Webhooks

| Command | Description |
|---------|-------------|
| `webhooks:list` | List all configured webhooks |
| `webhooks:create` | Create a webhook. Flags: `--url` (required), `--events` (required; comma-separated: `post.scheduled`, `post.published`, `post.failed`, `post.approved`, `post.rejected`). The signing secret is shown once |
| `webhooks:get <id>` | Webhook details |
| `webhooks:update <id>` | Update URL, events, or active state. Flags: `--url`, `--events`, `--active <true\|false>` |
| `webhooks:delete <id>` | Delete a webhook |
| `webhooks:rotate-secret <id>` | Rotate the signing secret; the new secret is shown once |

```bash
omnisocials webhooks:create \
  --url https://example.com/hooks/omnisocials \
  --events post.published,post.failed
```

`post.approved` and `post.rejected` fire when the review of a post in an approval workflow ends. To be told about both:

```bash
omnisocials webhooks:create \
  --url https://example.com/hooks/omnisocials \
  --events post.approved,post.rejected
```

Their payload names the decision, the approver and the reason; read the full review with [`posts:approval <id>`](/cli/posting).

See the [Webhooks guide](/webhooks) for event payloads and signature verification.
