From 6a69ac7eb44d4465e98d70dbeed132d49ef435e4 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 14 Feb 2026 11:42:56 +0700 Subject: [PATCH] feat: skill --- apps/cli/README.md | 757 ++++++++++++++++++--------- apps/cli/SKILL.md | 911 +++++++++++++++++++-------------- apps/cli/package.json | 2 +- apps/cli/src/commands/posts.ts | 21 +- apps/cli/src/index.ts | 43 +- 5 files changed, 1069 insertions(+), 665 deletions(-) diff --git a/apps/cli/README.md b/apps/cli/README.md index e679e88e..31c86fc0 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -1,254 +1,461 @@ # Postiz CLI -> Command-line interface for the Postiz social media scheduling platform +**Social media automation CLI for AI agents** - Schedule posts across 28+ platforms programmatically. -## Overview +The Postiz CLI provides a command-line interface to the Postiz API, enabling developers and AI agents to automate social media posting, manage content, and handle media uploads across platforms like Twitter/X, LinkedIn, Reddit, YouTube, TikTok, Instagram, Facebook, and more. -The Postiz CLI allows you to interact with the Postiz API from the command line, making it easy for developers and AI agents to automate social media scheduling, manage posts, and upload media. +--- -## Quick Start +## Installation -### Installation +### From npm (Recommended) ```bash -# Install dependencies +npm install -g postiz +# or +pnpm install -g postiz +``` + +### From Source + +```bash +git clone https://github.com/gitroomhq/postiz-app.git +cd postiz-app/apps/cli pnpm install - -# Build the CLI pnpm run build - -# Run locally (development) -pnpm run start -- [command] - -# Or link globally pnpm link --global ``` -### Setup +### For Development -Before using the CLI, you need to set your Postiz API key: +```bash +cd apps/cli +pnpm install +pnpm run build +pnpm link --global + +# Or run directly without linking +pnpm run start -- posts:list +``` + +--- + +## Setup + +**Required:** Set your Postiz API key ```bash export POSTIZ_API_KEY=your_api_key_here ``` -Optionally, you can set a custom API URL: +**Optional:** Custom API endpoint ```bash export POSTIZ_API_URL=https://your-custom-api.com ``` -## Usage +--- -```bash -postiz [options] -``` +## Commands -### Commands - -#### Create a Post - -```bash -postiz posts:create -c "Your content here" -i "integration-id-1,integration-id-2" -``` - -**Options:** -- `-c, --content ` - Post/comment content (can be used multiple times) -- `-m, --media ` - Comma-separated media URLs for the corresponding `-c` (can be used multiple times) -- `-i, --integrations ` - Comma-separated integration IDs (required) -- `-s, --schedule ` - Schedule date (ISO 8601) -- `-d, --delay ` - Delay between comments in milliseconds (default: 5000) -- `-p, --provider-type ` - Provider type for platform-specific settings (e.g., reddit, youtube, x, tiktok) -- `--settings ` - Provider-specific settings as JSON string - -**Examples:** - -```bash -# Simple post -postiz posts:create -c "Hello World!" -i "twitter-123" - -# Post with multiple images -postiz posts:create \ - -c "Check these out!" \ - -m "img1.jpg,img2.jpg,img3.jpg" \ - -i "twitter-123" - -# Post with comments, each having their own media -postiz posts:create \ - -c "Main post ๐Ÿš€" -m "main.jpg,main2.jpg" \ - -c "First comment ๐Ÿ“ธ" -m "comment1.jpg" \ - -c "Second comment ๐ŸŽจ" -m "comment2.jpg" \ - -i "twitter-123" - -# Comments can contain semicolons! -postiz posts:create \ - -c "Main post" \ - -c "Comment with semicolon; see, it works!" \ - -c "Another comment; multiple; semicolons!" \ - -i "twitter-123" - -# Twitter thread with custom delay -postiz posts:create \ - -c "Thread 1/3" \ - -c "Thread 2/3" \ - -c "Thread 3/3" \ - -d 2000 \ - -i "twitter-123" - -# Scheduled post -postiz posts:create \ - -c "Future post" \ - -s "2024-12-31T12:00:00Z" \ - -i "twitter-123" - -# With provider-specific settings -postiz posts:create \ - -c "Video description" \ - -p youtube \ - --settings '{"title":"My Video","type":"public"}' \ - -i "youtube-123" -``` - -### Provider-Specific Settings - -Many platforms support specific settings (Reddit subreddits, YouTube visibility, TikTok privacy, etc.): - -```bash -# Reddit with subreddit settings -postiz posts:create \ - -c "Post content" \ - -p reddit \ - --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}' \ - -i "reddit-123" - -# YouTube with title and visibility -postiz posts:create \ - -c "Video description" \ - -p youtube \ - --settings '{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}' \ - -i "youtube-123" - -# X (Twitter) with reply settings -postiz posts:create \ - -c "Tweet" \ - -p x \ - --settings '{"who_can_reply_post":"everyone"}' \ - -i "twitter-123" -``` - -See **[PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md)** for complete documentation on all platform-specific settings. -``` - -#### List Posts - -```bash -postiz posts:list [options] -``` - -**Options:** -- `-p, --page ` - Page number (default: 1) -- `-l, --limit ` - Posts per page (default: 10) -- `-s, --search ` - Search query - -**Examples:** - -```bash -# List all posts -postiz posts:list - -# With pagination -postiz posts:list -p 2 -l 20 - -# Search posts -postiz posts:list -s "keyword" -``` - -#### Delete a Post - -```bash -postiz posts:delete -``` - -**Example:** - -```bash -postiz posts:delete abc123xyz -``` - -#### List Integrations +### Discovery & Settings +**List all connected integrations** ```bash postiz integrations:list ``` -Shows all connected social media accounts. +Returns integration IDs, provider names, and metadata. -#### Upload a File +**Get integration settings schema** +```bash +postiz integrations:settings +``` +Returns character limits, required settings, and available tools for fetching dynamic data. + +**Trigger integration tools** +```bash +postiz integrations:trigger +postiz integrations:trigger -d '{"key":"value"}' +``` + +Fetch dynamic data like Reddit flairs, YouTube playlists, LinkedIn companies, etc. + +**Examples:** +```bash +# Get Reddit flairs +postiz integrations:trigger reddit-123 getFlairs -d '{"subreddit":"programming"}' + +# Get YouTube playlists +postiz integrations:trigger youtube-456 getPlaylists + +# Get LinkedIn companies +postiz integrations:trigger linkedin-789 getCompanies +``` + +--- + +### Creating Posts + +**Simple scheduled post** +```bash +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "integration-id" +``` + +**Draft post** +```bash +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -t draft -i "integration-id" +``` + +**Post with media** +```bash +postiz posts:create -c "Content" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "integration-id" +``` + +**Post with comments** (each comment can have its own media) +```bash +postiz posts:create \ + -c "Main post" -m "main.jpg" \ + -c "First comment" -m "comment1.jpg" \ + -c "Second comment" -m "comment2.jpg,comment3.jpg" \ + -s "2024-12-31T12:00:00Z" \ + -i "integration-id" +``` + +**Multi-platform post** +```bash +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "twitter-id,linkedin-id,facebook-id" +``` + +**Platform-specific settings** +```bash +postiz posts:create \ + -c "Content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"Post Title","type":"text"}}]}' \ + -i "reddit-id" +``` + +**Complex post from JSON file** +```bash +postiz posts:create --json post.json +``` + +**Options:** +- `-c, --content` - Post/comment content (use multiple times for posts with comments) +- `-s, --date` - Schedule date in ISO 8601 format (REQUIRED) +- `-t, --type` - Post type: "schedule" or "draft" (default: "schedule") +- `-m, --media` - Comma-separated media URLs for corresponding `-c` +- `-i, --integrations` - Comma-separated integration IDs (required) +- `-d, --delay` - Delay between comments in milliseconds (default: 5000) +- `--settings` - Platform-specific settings as JSON string +- `-j, --json` - Path to JSON file with full post structure +- `--shortLink` - Use short links (default: true) + +--- + +### Managing Posts + +**List posts** +```bash +postiz posts:list +postiz posts:list --startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z" +postiz posts:list --customer "customer-id" +``` + +Defaults to last 30 days to next 30 days if dates not specified. + +**Delete post** +```bash +postiz posts:delete +``` + +--- + +### Media Upload + +**Upload file and get URL** ```bash postiz upload ``` +**Supported formats:** +- **Images:** PNG, JPG, JPEG, GIF, WEBP, SVG, BMP, ICO +- **Videos:** MP4, MOV, AVI, MKV, WEBM, FLV, WMV, M4V, MPEG, MPG, 3GP +- **Audio:** MP3, WAV, OGG, AAC, FLAC, M4A +- **Documents:** PDF, DOC, DOCX + **Example:** +```bash +RESULT=$(postiz upload video.mp4) +PATH=$(echo "$RESULT" | jq -r '.path') +postiz posts:create -c "Check out my video!" -m "$PATH" -i "tiktok-id" +``` + +--- + +## Platform-Specific Features + +### Reddit +```bash +# Get available flairs +postiz integrations:trigger reddit-id getFlairs -d '{"subreddit":"programming"}' + +# Post with subreddit and flair +postiz posts:create \ + -c "Content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Post","type":"text","is_flair_required":true,"flair":{"id":"flair-123","name":"Discussion"}}}]}' \ + -i "reddit-id" +``` + +### YouTube +```bash +# Get playlists +postiz integrations:trigger youtube-id getPlaylists + +# Upload video with metadata +postiz posts:create \ + -c "Video description" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"title":"Video Title","type":"public","tags":[{"value":"tech","label":"Tech"}],"playlistId":"playlist-id"}' \ + -m "video.mp4" \ + -i "youtube-id" +``` + +### TikTok +```bash +postiz posts:create \ + -c "Video caption #fyp" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"privacy":"PUBLIC_TO_EVERYONE","duet":true,"stitch":true}' \ + -m "video.mp4" \ + -i "tiktok-id" +``` + +### LinkedIn +```bash +# Get companies you can post to +postiz integrations:trigger linkedin-id getCompanies + +# Post as company +postiz posts:create \ + -c "Company announcement" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"companyId":"company-123"}' \ + -i "linkedin-id" +``` + +### X (Twitter) +```bash +# Create thread +postiz posts:create \ + -c "Thread 1/3 ๐Ÿงต" \ + -c "Thread 2/3" \ + -c "Thread 3/3" \ + -s "2024-12-31T12:00:00Z" \ + -d 2000 \ + -i "twitter-id" + +# With reply settings +postiz posts:create \ + -c "Tweet content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"who_can_reply_post":"everyone"}' \ + -i "twitter-id" +``` + +### Instagram +```bash +# Regular post +postiz posts:create \ + -c "Caption #hashtag" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"post_type":"post"}' \ + -m "image.jpg" \ + -i "instagram-id" + +# Story +postiz posts:create \ + -c "" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"post_type":"story"}' \ + -m "story.jpg" \ + -i "instagram-id" +``` + +**See [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) for all 28+ platforms.** + +--- + +## Features for AI Agents + +### Discovery Workflow +The CLI enables dynamic discovery of integration capabilities: + +1. **List integrations** - Get available social media accounts +2. **Get settings** - Retrieve character limits, required fields, and available tools +3. **Trigger tools** - Fetch dynamic data (flairs, playlists, boards, etc.) +4. **Create posts** - Use discovered data in posts + +This allows AI agents to adapt to different platforms without hardcoded knowledge. + +### JSON Mode +For complex posts with multiple platforms and settings: ```bash -postiz upload ./images/photo.png +postiz posts:create --json complex-post.json ``` -## Development - -### Project Structure - -``` -apps/cli/ -โ”œโ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ index.ts # CLI entry point -โ”‚ โ”œโ”€โ”€ api.ts # API client -โ”‚ โ”œโ”€โ”€ config.ts # Configuration handler -โ”‚ โ””โ”€โ”€ commands/ -โ”‚ โ”œโ”€โ”€ posts.ts # Post commands -โ”‚ โ”œโ”€โ”€ integrations.ts # Integration commands -โ”‚ โ””โ”€โ”€ upload.ts # Upload commands -โ”œโ”€โ”€ package.json -โ”œโ”€โ”€ tsconfig.json -โ”œโ”€โ”€ tsup.config.ts -โ”œโ”€โ”€ README.md -โ””โ”€โ”€ SKILL.md # AI agent usage guide +JSON structure: +```json +{ + "integrations": ["twitter-123", "linkedin-456"], + "posts": [ + { + "provider": "twitter", + "post": [ + { + "content": "Tweet version", + "image": ["twitter-image.jpg"] + } + ] + }, + { + "provider": "linkedin", + "post": [ + { + "content": "LinkedIn version with more context...", + "image": ["linkedin-image.jpg"] + } + ], + "settings": { + "__type": "linkedin", + "companyId": "company-123" + } + } + ] +} ``` -### Scripts - -- `pnpm run dev` - Watch mode for development -- `pnpm run build` - Build the CLI -- `pnpm run start` - Run the built CLI - -### Building - -The CLI uses `tsup` for building: +### All Output is JSON +Every command outputs JSON for easy parsing: ```bash -pnpm run build +INTEGRATIONS=$(postiz integrations:list | jq -r '.') +REDDIT_ID=$(echo "$INTEGRATIONS" | jq -r '.[] | select(.identifier=="reddit") | .id') ``` -This creates a `dist/` directory with: -- Compiled JavaScript -- Type declarations -- Source maps -- Executable shebang for Node.js +### Threading Support +Comments are automatically converted to threads/replies based on platform: +- **Twitter/X**: Thread of tweets +- **Reddit**: Comment replies +- **LinkedIn**: Comment on post +- **Instagram**: First comment -## For AI Agents +```bash +postiz posts:create \ + -c "Main post" \ + -c "Comment 1" \ + -c "Comment 2" \ + -i "integration-id" +``` -See [SKILL.md](./SKILL.md) for detailed usage patterns and examples for AI agents. +--- -## API Reference +## Common Workflows + +### Reddit Post with Flair +```bash +#!/bin/bash +REDDIT_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="reddit") | .id') +FLAIRS=$(postiz integrations:trigger "$REDDIT_ID" getFlairs -d '{"subreddit":"programming"}') +FLAIR_ID=$(echo "$FLAIRS" | jq -r '.output[0].id') + +postiz posts:create \ + -c "My post content" \ + -s "2024-12-31T12:00:00Z" \ + --settings "{\"subreddit\":[{\"value\":{\"subreddit\":\"programming\",\"title\":\"Post Title\",\"type\":\"text\",\"is_flair_required\":true,\"flair\":{\"id\":\"$FLAIR_ID\",\"name\":\"Discussion\"}}}]}" \ + -i "$REDDIT_ID" +``` + +### YouTube Video Upload +```bash +#!/bin/bash +VIDEO=$(postiz upload video.mp4) +VIDEO_PATH=$(echo "$VIDEO" | jq -r '.path') + +postiz posts:create \ + -c "Video description..." \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}' \ + -m "$VIDEO_PATH" \ + -i "youtube-id" +``` + +### Multi-Platform Campaign +```bash +#!/bin/bash +postiz posts:create \ + -c "Same content everywhere" \ + -s "2024-12-31T12:00:00Z" \ + -m "image.jpg" \ + -i "twitter-id,linkedin-id,facebook-id" +``` + +### Batch Scheduling +```bash +#!/bin/bash +DATES=("2024-02-14T09:00:00Z" "2024-02-15T09:00:00Z" "2024-02-16T09:00:00Z") +CONTENT=("Monday motivation ๐Ÿ’ช" "Tuesday tips ๐Ÿ’ก" "Wednesday wisdom ๐Ÿง ") + +for i in "${!DATES[@]}"; do + postiz posts:create \ + -c "${CONTENT[$i]}" \ + -s "${DATES[$i]}" \ + -i "twitter-id" +done +``` + +--- + +## Documentation + +**For AI Agents:** +- **[SKILL.md](./SKILL.md)** - Complete skill reference with patterns and examples + +**Deep-Dive Guides:** +- **[HOW_TO_RUN.md](./HOW_TO_RUN.md)** - Installation and setup methods +- **[COMMAND_LINE_GUIDE.md](./COMMAND_LINE_GUIDE.md)** - Complete command syntax reference +- **[PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md)** - All platform settings schemas +- **[INTEGRATION_TOOLS_WORKFLOW.md](./INTEGRATION_TOOLS_WORKFLOW.md)** - Tools workflow guide +- **[INTEGRATION_SETTINGS_DISCOVERY.md](./INTEGRATION_SETTINGS_DISCOVERY.md)** - Settings discovery +- **[SUPPORTED_FILE_TYPES.md](./SUPPORTED_FILE_TYPES.md)** - Media format reference +- **[PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md)** - Code architecture +- **[PUBLISHING.md](./PUBLISHING.md)** - npm publishing guide + +**Examples:** +- **[examples/EXAMPLES.md](./examples/EXAMPLES.md)** - Comprehensive examples +- **[examples/](./examples/)** - Ready-to-use scripts and JSON files + +--- + +## API Endpoints The CLI interacts with these Postiz API endpoints: -- `POST /public/v1/posts` - Create a post -- `GET /public/v1/posts` - List posts -- `DELETE /public/v1/posts/:id` - Delete a post -- `GET /public/v1/integrations` - List integrations -- `POST /public/v1/upload` - Upload media +| Endpoint | Method | Purpose | +|----------|--------|---------| +| `/public/v1/posts` | POST | Create a post | +| `/public/v1/posts` | GET | List posts | +| `/public/v1/posts/:id` | DELETE | Delete a post | +| `/public/v1/integrations` | GET | List integrations | +| `/public/v1/integration-settings/:id` | GET | Get integration settings | +| `/public/v1/integration-trigger/:id` | POST | Trigger integration tool | +| `/public/v1/upload` | POST | Upload media | + +--- ## Environment Variables @@ -257,65 +464,147 @@ The CLI interacts with these Postiz API endpoints: | `POSTIZ_API_KEY` | โœ… Yes | - | Your Postiz API key | | `POSTIZ_API_URL` | No | `https://api.postiz.com` | Custom API endpoint | +--- + ## Error Handling -The CLI provides user-friendly error messages: +The CLI provides clear error messages with exit codes: -- โœ… Success messages with green checkmarks -- โŒ Error messages with red X marks -- ๐Ÿ“‹ Info messages with emojis -- Exit code 0 for success, 1 for errors +- **Exit code 0**: Success +- **Exit code 1**: Error occurred -## Examples +**Common errors:** -### Basic Workflow +| Error | Solution | +|-------|----------| +| `POSTIZ_API_KEY is not set` | Set environment variable: `export POSTIZ_API_KEY=key` | +| `Integration not found` | Run `integrations:list` to get valid IDs | +| `startDate/endDate required` | Use ISO 8601 format: `"2024-12-31T12:00:00Z"` | +| `Invalid settings` | Check `integrations:settings` for required fields | +| `Tool not found` | Check available tools in `integrations:settings` output | +| `Upload failed` | Verify file exists and format is supported | + +--- + +## Development + +### Project Structure + +``` +apps/cli/ +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ index.ts # CLI entry point with yargs +โ”‚ โ”œโ”€โ”€ api.ts # PostizAPI client class +โ”‚ โ”œโ”€โ”€ config.ts # Environment configuration +โ”‚ โ””โ”€โ”€ commands/ +โ”‚ โ”œโ”€โ”€ posts.ts # Post management commands +โ”‚ โ”œโ”€โ”€ integrations.ts # Integration commands +โ”‚ โ””โ”€โ”€ upload.ts # Media upload command +โ”œโ”€โ”€ examples/ # Example scripts and JSON files +โ”œโ”€โ”€ package.json +โ”œโ”€โ”€ tsconfig.json +โ”œโ”€โ”€ tsup.config.ts # Build configuration +โ”œโ”€โ”€ README.md # This file +โ””โ”€โ”€ SKILL.md # AI agent reference +``` + +### Scripts ```bash -# 1. Set API key +pnpm run dev # Watch mode for development +pnpm run build # Build the CLI +pnpm run start # Run the built CLI +``` + +### Building + +The CLI uses `tsup` for bundling: + +```bash +pnpm run build +``` + +Output in `dist/`: +- `index.js` - Bundled executable with shebang +- `index.js.map` - Source map + +--- + +## Quick Reference + +```bash +# Environment setup export POSTIZ_API_KEY=your_key -# 2. Check connected integrations -postiz integrations:list +# Discovery +postiz integrations:list # List integrations +postiz integrations:settings # Get settings +postiz integrations:trigger -d '{}' # Fetch data -# 3. Create a post -postiz posts:create -c "Hello from CLI!" -i "twitter-123" +# Posting (date is required) +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -i "id" # Simple +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -t draft -i "id" # Draft +postiz posts:create -c "text" -m "img.jpg" -s "2024-12-31T12:00:00Z" -i "id" # With media +postiz posts:create -c "main" -c "comment" -s "2024-12-31T12:00:00Z" -i "id" # With comment +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" --settings '{}' -i "id" # Platform-specific +postiz posts:create --json file.json # Complex -# 4. List posts -postiz posts:list +# Management +postiz posts:list # List posts +postiz posts:delete # Delete post +postiz upload # Upload media -# 5. Delete a post -postiz posts:delete post-id-123 +# Help +postiz --help # Show help +postiz posts:create --help # Command help ``` -### Scheduled Posting - -```bash -# Schedule posts for different times -postiz posts:create -c "Morning post" -s "2024-01-15T09:00:00Z" -postiz posts:create -c "Afternoon post" -s "2024-01-15T15:00:00Z" -postiz posts:create -c "Evening post" -s "2024-01-15T20:00:00Z" -``` - -### Media Upload Workflow - -```bash -# Upload an image -postiz upload ./image.png - -# The response includes the URL, use it in a post -postiz posts:create -c "Check this out!" --image "url-from-upload" -``` +--- ## Contributing This CLI is part of the [Postiz monorepo](https://github.com/gitroomhq/postiz-app). +To contribute: +1. Fork the repository +2. Create a feature branch +3. Make your changes in `apps/cli/` +4. Run tests: `pnpm run build` +5. Submit a pull request + +--- + ## License AGPL-3.0 +--- + ## Links -- [Postiz Website](https://postiz.com) -- [API Documentation](https://postiz.com/api-docs) -- [GitHub Repository](https://github.com/gitroomhq/postiz-app) +- **Website:** [postiz.com](https://postiz.com) +- **API Docs:** [postiz.com/api-docs](https://postiz.com/api-docs) +- **GitHub:** [gitroomhq/postiz-app](https://github.com/gitroomhq/postiz-app) +- **Issues:** [Report bugs](https://github.com/gitroomhq/postiz-app/issues) + +--- + +## Supported Platforms + +28+ platforms including: + +| Platform | Integration Tools | Settings | +|----------|------------------|----------| +| Twitter/X | getLists, getCommunities | who_can_reply_post | +| LinkedIn | getCompanies | companyId, carousel | +| Reddit | getFlairs, searchSubreddits | subreddit, title, flair | +| YouTube | getPlaylists, getCategories | title, type, tags, playlistId | +| TikTok | - | privacy, duet, stitch | +| Instagram | - | post_type (post/story) | +| Facebook | getPages | - | +| Pinterest | getBoards, getBoardSections | - | +| Discord | getChannels | - | +| Slack | getChannels | - | +| And 18+ more... | | | + +**See [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) for complete documentation.** diff --git a/apps/cli/SKILL.md b/apps/cli/SKILL.md index 2156620c..ba272887 100644 --- a/apps/cli/SKILL.md +++ b/apps/cli/SKILL.md @@ -1,468 +1,585 @@ -# Postiz CLI Skill +| Property | Value | +|----------|-------| +| **name** | postiz | +| **description** | Social media automation CLI for scheduling posts across 28+ platforms | +| **allowed-tools** | Bash(postiz:*) | -## Description +--- -The Postiz CLI is a command-line interface for interacting with the Postiz social media scheduling API. It allows AI agents and developers to programmatically manage posts, integrations, and media uploads. +## Core Workflow -## Prerequisites +The fundamental pattern for using Postiz CLI: -- API Key: You need a valid Postiz API key -- Set the environment variable: `export POSTIZ_API_KEY=your_api_key` -- Optional: Set custom API URL with `export POSTIZ_API_URL=https://your-api-url.com` - -## Installation +1. **Discover** - List integrations and get their settings +2. **Fetch** - Use integration tools to retrieve dynamic data (flairs, playlists, companies) +3. **Prepare** - Upload media files if needed +4. **Post** - Create posts with content, media, and platform-specific settings ```bash -# From the monorepo root -pnpm install +# 1. Discover +postiz integrations:list +postiz integrations:settings -# Build the CLI -pnpm --filter postiz run build +# 2. Fetch (if needed) +postiz integrations:trigger -d '{"key":"value"}' -# Link globally (optional) -cd apps/cli -pnpm link --global +# 3. Prepare +postiz upload image.jpg + +# 4. Post +postiz posts:create -c "Content" -m "image.jpg" -i "" ``` -## Available Commands +--- -### Posts Management +## Essential Commands -#### Create a Post - -The CLI supports both **simple** and **complex** post creation: - -##### Simple Post Creation (Command-line) +### Setup ```bash -postiz posts:create -c "Your post content" -i "integration-id-1,integration-id-2" +# Required environment variable +export POSTIZ_API_KEY=your_api_key_here + +# Optional custom API URL +export POSTIZ_API_URL=https://custom-api-url.com ``` -Options: -- `-c, --content `: Post content/text -- `-i, --integrations `: Comma-separated integration IDs (required) -- `-s, --schedule `: Schedule date in ISO 8601 format -- `--image `: Comma-separated image URLs or paths (multiple images supported) -- `--comments `: Semicolon-separated comments -- `--shortLink`: Use URL shortener (default: true) - -Examples: -```bash -# Create immediate post -postiz posts:create -c "Hello World!" -i "twitter-123,linkedin-456" - -# Create scheduled post -postiz posts:create -c "Future post" -s "2024-12-31T12:00:00Z" -i "twitter-123" - -# Create post with multiple images -postiz posts:create -c "Check these out!" --image "url1.jpg,url2.jpg,url3.jpg" -i "twitter-123" - -# Create post with comments (simple) -postiz posts:create -c "Main post" --comments "First comment;Second comment" -i "twitter-123" -``` - -##### Complex Post Creation (JSON File) - -For posts with **comments that have their own media**, use JSON files: +### Integration Discovery ```bash -postiz posts:create --json ./my-post.json +# List all connected integrations +postiz integrations:list + +# Get settings schema for specific integration +postiz integrations:settings + +# Trigger integration tool to fetch dynamic data +postiz integrations:trigger +postiz integrations:trigger -d '{"param":"value"}' ``` -**JSON Structure:** -```json -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [ - { - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "Main post with media ๐Ÿš€", - "image": [ - { "id": "img1", "path": "https://example.com/main1.jpg" }, - { "id": "img2", "path": "https://example.com/main2.jpg" } - ] - }, - { - "content": "First comment with its own media ๐Ÿ“ธ", - "image": [ - { "id": "img3", "path": "https://example.com/comment1.jpg" } - ], - "delay": 5000 - }, - { - "content": "Second comment with different media ๐ŸŽจ", - "image": [ - { "id": "img4", "path": "https://example.com/comment2.jpg" } - ], - "delay": 10000 - } - ], - "settings": { "__type": "EmptySettings" } - } - ] -} -``` +### Creating Posts -**Key Features:** -- โœ… **Multiple posts** to different platforms in one request -- โœ… **Each post can have multiple values** (main post + comments/thread) -- โœ… **Each value can have multiple images** (array of MediaDto) -- โœ… **Delays between comments** (in milliseconds) -- โœ… **Platform-specific content** (different content per integration) - -See `examples/` directory for: -- `post-with-comments.json` - Post with comments, each having their own media -- `multi-platform-post.json` - Post to multiple platforms with different content -- `thread-post.json` - Create a Twitter thread with 5 tweets -- `EXAMPLES.md` - Comprehensive guide with all use cases - -#### List Posts ```bash -postiz posts:list +# Simple post (date is REQUIRED) +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "integration-id" + +# Draft post +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -t draft -i "integration-id" + +# Post with media +postiz posts:create -c "Content" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "integration-id" + +# Post with comments (each with own media) +postiz posts:create \ + -c "Main post" -m "main.jpg" \ + -c "First comment" -m "comment1.jpg" \ + -c "Second comment" -m "comment2.jpg,comment3.jpg" \ + -s "2024-12-31T12:00:00Z" \ + -i "integration-id" + +# Multi-platform post +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "twitter-id,linkedin-id,facebook-id" + +# Platform-specific settings +postiz posts:create \ + -c "Content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Post","type":"text"}}]}' \ + -i "reddit-id" + +# Complex post from JSON file +postiz posts:create --json post.json ``` -Options: -- `-p, --page `: Page number (default: 1) -- `-l, --limit `: Posts per page (default: 10) -- `-s, --search `: Search query +### Managing Posts -Examples: ```bash -# List all posts +# List posts (defaults to last 30 days to next 30 days) postiz posts:list -# List with pagination -postiz posts:list -p 2 -l 20 +# List posts in date range +postiz posts:list --startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z" -# Search posts -postiz posts:list -s "hello" -``` - -#### Delete a Post -```bash +# Delete post postiz posts:delete ``` -Example: -```bash -postiz posts:delete abc123xyz -``` - -### Integrations - -#### List Connected Integrations -```bash -postiz integrations:list -``` - -This command shows all connected social media accounts and their IDs, which can be used when creating posts. - ### Media Upload -#### Upload a File ```bash -postiz upload +# Upload file and get URL +postiz upload image.jpg + +# Supports: images (PNG, JPG, GIF, WEBP, SVG), videos (MP4, MOV, AVI, MKV, WEBM), +# audio (MP3, WAV, OGG, AAC), documents (PDF, DOC, DOCX) ``` -Example: +--- + +## Common Patterns + +### Pattern 1: Discover & Use Integration Tools + +**Reddit - Get flairs for a subreddit:** ```bash -postiz upload ./images/photo.png +# Get Reddit integration ID +REDDIT_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="reddit") | .id') + +# Fetch available flairs +FLAIRS=$(postiz integrations:trigger "$REDDIT_ID" getFlairs -d '{"subreddit":"programming"}') +FLAIR_ID=$(echo "$FLAIRS" | jq -r '.output[0].id') + +# Use in post +postiz posts:create \ + -c "My post content" \ + -s "2024-12-31T12:00:00Z" \ + --settings "{\"subreddit\":[{\"value\":{\"subreddit\":\"programming\",\"title\":\"Post Title\",\"type\":\"text\",\"is_flair_required\":true,\"flair\":{\"id\":\"$FLAIR_ID\",\"name\":\"Discussion\"}}}]}" \ + -i "$REDDIT_ID" ``` -Supported formats: PNG, JPG, JPEG, GIF +**YouTube - Get playlists:** +```bash +YOUTUBE_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="youtube") | .id') +PLAYLISTS=$(postiz integrations:trigger "$YOUTUBE_ID" getPlaylists) +PLAYLIST_ID=$(echo "$PLAYLISTS" | jq -r '.output[0].id') -## Usage for AI Agents +postiz posts:create \ + -c "Video description" \ + -s "2024-12-31T12:00:00Z" \ + --settings "{\"title\":\"My Video\",\"type\":\"public\",\"playlistId\":\"$PLAYLIST_ID\"}" \ + -m "video.mp4" \ + -i "$YOUTUBE_ID" +``` -AI agents can use this CLI to automate social media scheduling. The CLI supports both simple and advanced post structures, including posts with comments where each has its own media. +**LinkedIn - Post as company:** +```bash +LINKEDIN_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="linkedin") | .id') +COMPANIES=$(postiz integrations:trigger "$LINKEDIN_ID" getCompanies) +COMPANY_ID=$(echo "$COMPANIES" | jq -r '.output[0].id') -### Understanding the Post Structure +postiz posts:create \ + -c "Company announcement" \ + -s "2024-12-31T12:00:00Z" \ + --settings "{\"companyId\":\"$COMPANY_ID\"}" \ + -i "$LINKEDIN_ID" +``` -```typescript -CreatePostDto { - type: 'now' | 'schedule' | 'draft' | 'update', - date: string, // ISO 8601 timestamp - shortLink: boolean, // Enable URL shortening - tags: Tag[], // Array of tags - posts: [ // Can post to multiple platforms +### Pattern 2: Upload Media Before Posting + +```bash +# Upload multiple files +VIDEO_RESULT=$(postiz upload video.mp4) +VIDEO_PATH=$(echo "$VIDEO_RESULT" | jq -r '.path') + +THUMB_RESULT=$(postiz upload thumbnail.jpg) +THUMB_PATH=$(echo "$THUMB_RESULT" | jq -r '.path') + +# Use in post +postiz posts:create \ + -c "Check out my video!" \ + -s "2024-12-31T12:00:00Z" \ + -m "$VIDEO_PATH" \ + -i "tiktok-id" +``` + +### Pattern 3: Twitter Thread + +```bash +postiz posts:create \ + -c "๐Ÿงต Thread starter (1/4)" -m "intro.jpg" \ + -c "Point one (2/4)" -m "point1.jpg" \ + -c "Point two (3/4)" -m "point2.jpg" \ + -c "Conclusion (4/4)" -m "outro.jpg" \ + -s "2024-12-31T12:00:00Z" \ + -d 2000 \ + -i "twitter-id" +``` + +### Pattern 4: Multi-Platform Campaign + +```bash +# Create JSON file with platform-specific content +cat > campaign.json << 'EOF' +{ + "integrations": ["twitter-123", "linkedin-456", "facebook-789"], + "posts": [ { - integration: { id: string }, // Platform integration ID - value: [ // Main post + comments/thread + "provider": "twitter", + "post": [ { - content: string, // Text content - image: MediaDto[], // Array of media (multiple images) - delay?: number, // Delay in ms (for comments) - id?: string // Optional ID + "content": "Short tweet version #tech", + "image": ["twitter-image.jpg"] } - ], - settings: { __type: 'EmptySettings' } + ] + }, + { + "provider": "linkedin", + "post": [ + { + "content": "Professional LinkedIn version with more context...", + "image": ["linkedin-image.jpg"] + } + ] } ] } -``` - -### Common Patterns - -### Pattern 1: Create and Schedule Multiple Posts -```bash -# Set API key once -export POSTIZ_API_KEY=your_key - -# Create posts programmatically -postiz posts:create -c "Morning update" -s "2024-01-15T09:00:00Z" -i "twitter-123" -postiz posts:create -c "Afternoon update" -s "2024-01-15T15:00:00Z" -i "twitter-123" -postiz posts:create -c "Evening update" -s "2024-01-15T20:00:00Z" -i "twitter-123" -``` - -### Pattern 2: Upload Media and Create Post -```bash -# First, upload the media -UPLOAD_RESULT=$(postiz upload ./image.png) - -# Extract the URL from the result (you'll need to parse the JSON) -# Then create post with the media URL -postiz posts:create -c "Check out this image!" --image "" -``` - -### Pattern 3: Check Integrations Before Posting -```bash -# List available integrations -postiz integrations:list - -# Use the integration IDs from the response to create posts -postiz posts:create -c "Multi-platform post" -i "twitter-123,linkedin-456,facebook-789" -``` - -### Pattern 4: Manage Existing Posts -```bash -# List all posts to get IDs -postiz posts:list - -# Delete a specific post -postiz posts:delete -``` - -### Pattern 5: Create Post with Comments and Media (Advanced) - -```bash -# Create a JSON file programmatically -cat > post.json << 'EOF' -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "Main post with 2 images ๐Ÿš€", - "image": [ - { "id": "1", "path": "https://example.com/img1.jpg" }, - { "id": "2", "path": "https://example.com/img2.jpg" } - ] - }, - { - "content": "First comment with its own image ๐Ÿ“ธ", - "image": [ - { "id": "3", "path": "https://example.com/comment-img.jpg" } - ], - "delay": 5000 - } - ], - "settings": { "__type": "EmptySettings" } - }] -} EOF -# Post it -postiz posts:create --json post.json +postiz posts:create --json campaign.json ``` -### Pattern 6: Multi-Platform Campaign +### Pattern 5: Validate Settings Before Posting ```javascript -// AI Agent: Create coordinated multi-platform posts -const campaign = { - type: "schedule", - date: "2024-12-25T12:00:00Z", - shortLink: true, - tags: [{ value: "campaign", label: "Campaign" }], - posts: [ - { - integration: { id: "twitter-123" }, - value: [{ - content: "Twitter-optimized content ๐Ÿฆ", - image: [{ id: "t1", path: "twitter-image.jpg" }] - }] - }, - { - integration: { id: "linkedin-456" }, - value: [{ - content: "Professional LinkedIn content ๐Ÿ’ผ", - image: [{ id: "l1", path: "linkedin-image.jpg" }] - }] - }, - { - integration: { id: "facebook-789" }, - value: [ - { - content: "Facebook main post ๐Ÿ“ฑ", - image: [{ id: "f1", path: "facebook-main.jpg" }] - }, - { - content: "Additional context in comments", - image: [{ id: "f2", path: "facebook-comment.jpg" }], - delay: 300000 // 5 minutes later - } - ] - } - ] -}; +const { execSync } = require('child_process'); -require('fs').writeFileSync('campaign.json', JSON.stringify(campaign, null, 2)); -execSync('postiz posts:create --json campaign.json'); -``` +function validateAndPost(content, integrationId, settings) { + // Get integration settings + const settingsResult = execSync( + `postiz integrations:settings ${integrationId}`, + { encoding: 'utf-8' } + ); + const schema = JSON.parse(settingsResult); -### Pattern 7: Twitter Thread Creation - -```bash -# Create a thread with multiple tweets, each with media -postiz posts:create --json - << 'EOF' -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "๐Ÿงต Thread about X (1/3)", - "image": [{ "id": "1", "path": "https://example.com/thread-1.jpg" }] - }, - { - "content": "Key point number 1 (2/3)", - "image": [{ "id": "2", "path": "https://example.com/thread-2.jpg" }], - "delay": 2000 - }, - { - "content": "Conclusion and CTA (3/3)", - "image": [{ "id": "3", "path": "https://example.com/thread-3.jpg" }], - "delay": 2000 - } - ], - "settings": { "__type": "EmptySettings" } - }] -} -EOF -``` - -### Pattern 8: Upload Media, Then Post - -```bash -# 1. Upload images first -IMG1=$(postiz upload ./image1.jpg | jq -r '.path') -IMG2=$(postiz upload ./image2.jpg | jq -r '.path') - -# 2. Create post with uploaded images -cat > post.json << EOF -{ - "type": "now", - "date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "twitter-123" }, - "value": [{ - "content": "Check out these images!", - "image": [ - { "id": "img1", "path": "$IMG1" }, - { "id": "img2", "path": "$IMG2" } - ] - }], - "settings": { "__type": "EmptySettings" } - }] -} -EOF - -postiz posts:create --json post.json -``` - -## Output Format - -All commands return JSON output, making it easy for AI agents to parse and process results: - -```json -{ - "success": true, - "data": { - "id": "post-123", - "content": "Hello World!", - "scheduledDate": "2024-01-15T12:00:00Z" + // Check character limit + if (content.length > schema.output.maxLength) { + console.warn(`Content exceeds ${schema.output.maxLength} chars, truncating...`); + content = content.substring(0, schema.output.maxLength - 3) + '...'; } + + // Create post + const result = execSync( + `postiz posts:create -c "${content}" -s "2024-12-31T12:00:00Z" --settings '${JSON.stringify(settings)}' -i "${integrationId}"`, + { encoding: 'utf-8' } + ); + + return JSON.parse(result); } ``` -## Error Handling - -The CLI provides clear error messages: - -- Missing API key: `โŒ Error: POSTIZ_API_KEY environment variable is required` -- API errors: `โŒ API Error (status): message` -- File not found: `โŒ Failed to upload file: message` - -Exit codes: -- `0`: Success -- `1`: Error occurred - -## Environment Variables - -| Variable | Required | Default | Description | -|----------|----------|---------|-------------| -| `POSTIZ_API_KEY` | Yes | - | Your Postiz API key | -| `POSTIZ_API_URL` | No | `https://api.postiz.com` | Custom API endpoint | - -## Tips for AI Agents - -1. **Always set the API key** before running commands -2. **Parse JSON output** using tools like `jq` for scripting -3. **Check exit codes** to determine if commands succeeded -4. **Use integrations:list** first to get valid integration IDs -5. **Schedule posts** in the future using ISO 8601 date format -6. **Upload media first** before referencing in posts - -## Example Workflow Script +### Pattern 6: Batch Scheduling ```bash #!/bin/bash -# Set API key -export POSTIZ_API_KEY="your-api-key-here" +# Schedule posts for the week +DATES=( + "2024-02-14T09:00:00Z" + "2024-02-15T09:00:00Z" + "2024-02-16T09:00:00Z" +) -# Get integrations -INTEGRATIONS=$(postiz integrations:list) -echo "Available integrations: $INTEGRATIONS" +CONTENT=( + "Monday motivation ๐Ÿ’ช" + "Tuesday tips ๐Ÿ’ก" + "Wednesday wisdom ๐Ÿง " +) -# Create a post -postiz posts:create \ - -c "Automated post from AI agent" \ - -s "2024-12-25T12:00:00Z" \ - -i "twitter-123,linkedin-456" - -# List all posts -postiz posts:list -l 5 - -echo "โœ… Workflow completed!" +for i in "${!DATES[@]}"; do + postiz posts:create \ + -c "${CONTENT[$i]}" \ + -s "${DATES[$i]}" \ + -i "twitter-id" \ + -m "post-${i}.jpg" + echo "Scheduled: ${CONTENT[$i]} for ${DATES[$i]}" +done ``` -## Support +### Pattern 7: Error Handling & Retry -For issues or questions: -- GitHub: https://github.com/gitroomhq/postiz-app -- Documentation: https://postiz.com/docs -- API Reference: https://postiz.com/api-docs +```javascript +const { execSync } = require('child_process'); + +async function postWithRetry(content, integrationId, date, maxRetries = 3) { + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + const result = execSync( + `postiz posts:create -c "${content}" -s "${date}" -i "${integrationId}"`, + { encoding: 'utf-8', stdio: 'pipe' } + ); + console.log('โœ… Post created successfully'); + return JSON.parse(result); + } catch (error) { + console.error(`โŒ Attempt ${attempt} failed: ${error.message}`); + + if (attempt < maxRetries) { + const delay = Math.pow(2, attempt) * 1000; // Exponential backoff + console.log(`โณ Retrying in ${delay}ms...`); + await new Promise(resolve => setTimeout(resolve, delay)); + } else { + throw new Error(`Failed after ${maxRetries} attempts`); + } + } + } +} +``` + +--- + +## Technical Concepts + +### Integration Tools Workflow + +Many integrations require dynamic data (IDs, tags, playlists) that can't be hardcoded. The tools workflow enables discovery and usage: + +1. **Check available tools** - `integrations:settings` returns a `tools` array +2. **Review tool schema** - Each tool has `methodName`, `description`, and `dataSchema` +3. **Trigger tool** - Call `integrations:trigger` with required parameters +4. **Use output** - Tool returns data to use in post settings + +**Example tools by platform:** +- **Reddit**: `getFlairs`, `searchSubreddits`, `getSubreddits` +- **YouTube**: `getPlaylists`, `getCategories`, `getChannels` +- **LinkedIn**: `getCompanies`, `getOrganizations` +- **Twitter/X**: `getListsowned`, `getCommunities` +- **Pinterest**: `getBoards`, `getBoardSections` + +### Provider Settings Structure + +Platform-specific settings use a discriminator pattern with `__type` field: + +```json +{ + "posts": [ + { + "provider": "reddit", + "post": [{ "content": "...", "image": [...] }], + "settings": { + "__type": "reddit", + "subreddit": [{ + "value": { + "subreddit": "programming", + "title": "Post Title", + "type": "text", + "url": "", + "is_flair_required": false + } + }] + } + } + ] +} +``` + +Pass settings directly: +```bash +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" --settings '{"subreddit":[...]}' -i "reddit-id" +# Backend automatically adds "__type" based on integration ID +``` + +### Comments and Threading + +Posts can have comments (threads on Twitter/X, replies elsewhere). Each comment can have its own media: + +```bash +# Using multiple -c and -m flags +postiz posts:create \ + -c "Main post" -m "image1.jpg,image2.jpg" \ + -c "Comment 1" -m "comment-img.jpg" \ + -c "Comment 2" -m "another.jpg,more.jpg" \ + -s "2024-12-31T12:00:00Z" \ + -d 5000 \ # Delay between comments in ms + -i "integration-id" +``` + +Internally creates: +```json +{ + "posts": [{ + "value": [ + { "content": "Main post", "image": ["image1.jpg", "image2.jpg"] }, + { "content": "Comment 1", "image": ["comment-img.jpg"], "delay": 5000 }, + { "content": "Comment 2", "image": ["another.jpg", "more.jpg"], "delay": 5000 } + ] + }] +} +``` + +### Date Handling + +All dates use ISO 8601 format: +- Schedule posts: `-s "2024-12-31T12:00:00Z"` +- List posts: `--startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z"` +- Defaults: `posts:list` uses 30 days ago to 30 days from now + +### Media Upload Response + +Upload returns JSON with path and metadata: +```json +{ + "path": "https://cdn.postiz.com/uploads/abc123.jpg", + "size": 123456, + "type": "image/jpeg" +} +``` + +Extract path for use in posts: +```bash +RESULT=$(postiz upload image.jpg) +PATH=$(echo "$RESULT" | jq -r '.path') +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -m "$PATH" -i "integration-id" +``` + +### JSON Mode vs CLI Flags + +**CLI flags** - Quick posts: +```bash +postiz posts:create -c "Content" -m "img.jpg" -i "twitter-id" +``` + +**JSON mode** - Complex posts with multiple platforms and settings: +```bash +postiz posts:create --json post.json +``` + +JSON mode supports: +- Multiple platforms with different content per platform +- Complex provider-specific settings +- Scheduled posts +- Posts with many comments +- Custom delay between comments + +--- + +## Platform-Specific Examples + +### Reddit +```bash +postiz posts:create \ + -c "Post content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}' \ + -i "reddit-id" +``` + +### YouTube +```bash +postiz posts:create \ + -c "Video description" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"title":"Video Title","type":"public","tags":[{"value":"tech","label":"Tech"}]}' \ + -m "video.mp4" \ + -i "youtube-id" +``` + +### TikTok +```bash +postiz posts:create \ + -c "Video caption #fyp" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"privacy":"PUBLIC_TO_EVERYONE","duet":true,"stitch":true}' \ + -m "video.mp4" \ + -i "tiktok-id" +``` + +### X (Twitter) +```bash +postiz posts:create \ + -c "Tweet content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"who_can_reply_post":"everyone"}' \ + -i "twitter-id" +``` + +### LinkedIn +```bash +# Personal post +postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "linkedin-id" + +# Company post +postiz posts:create \ + -c "Content" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"companyId":"company-123"}' \ + -i "linkedin-id" +``` + +### Instagram +```bash +# Regular post +postiz posts:create \ + -c "Caption #hashtag" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"post_type":"post"}' \ + -m "image.jpg" \ + -i "instagram-id" + +# Story +postiz posts:create \ + -c "" \ + -s "2024-12-31T12:00:00Z" \ + --settings '{"post_type":"story"}' \ + -m "story.jpg" \ + -i "instagram-id" +``` + +--- + +## Supporting Resources + +**Deep-dive documentation:** +- [HOW_TO_RUN.md](./HOW_TO_RUN.md) - Installation and setup methods +- [COMMAND_LINE_GUIDE.md](./COMMAND_LINE_GUIDE.md) - Complete command syntax reference +- [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) - All 28+ platform settings schemas +- [INTEGRATION_TOOLS_WORKFLOW.md](./INTEGRATION_TOOLS_WORKFLOW.md) - Complete tools workflow guide +- [INTEGRATION_SETTINGS_DISCOVERY.md](./INTEGRATION_SETTINGS_DISCOVERY.md) - Settings discovery workflow +- [SUPPORTED_FILE_TYPES.md](./SUPPORTED_FILE_TYPES.md) - All supported media formats +- [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) - Code architecture +- [PUBLISHING.md](./PUBLISHING.md) - npm publishing guide + +**Ready-to-use examples:** +- [examples/EXAMPLES.md](./examples/EXAMPLES.md) - Comprehensive examples +- [examples/basic-usage.sh](./examples/basic-usage.sh) - Shell script basics +- [examples/ai-agent-example.js](./examples/ai-agent-example.js) - Node.js agent +- [examples/post-with-comments.json](./examples/post-with-comments.json) - Threading example +- [examples/multi-platform-with-settings.json](./examples/multi-platform-with-settings.json) - Campaign example +- [examples/youtube-video.json](./examples/youtube-video.json) - YouTube with tags +- [examples/reddit-post.json](./examples/reddit-post.json) - Reddit with subreddit +- [examples/tiktok-video.json](./examples/tiktok-video.json) - TikTok with privacy + +--- + +## Common Gotchas + +1. **API Key not set** - Always `export POSTIZ_API_KEY=key` before using CLI +2. **Invalid integration ID** - Run `integrations:list` to get current IDs +3. **Settings schema mismatch** - Check `integrations:settings` for required fields +4. **Media upload before posting** - Upload returns URL to use in `-m` flag +5. **JSON escaping in shell** - Use single quotes for JSON: `--settings '{...}'` +6. **Date format** - Must be ISO 8601: `"2024-12-31T12:00:00Z"` +7. **Tool not found** - Check available tools in `integrations:settings` output +8. **Character limits** - Each platform has different limits, check `maxLength` in settings +9. **Required settings** - Some platforms require specific settings (Reddit needs title, YouTube needs title) +10. **Media MIME types** - CLI auto-detects from file extension, ensure correct extension + +--- + +## Quick Reference + +```bash +# Environment +export POSTIZ_API_KEY=key + +# Discovery +postiz integrations:list # Get integration IDs +postiz integrations:settings # Get settings schema +postiz integrations:trigger -d '{}' # Fetch dynamic data + +# Posting (date is REQUIRED) +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -i "id" # Simple +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -t draft -i "id" # Draft +postiz posts:create -c "text" -m "img.jpg" -s "2024-12-31T12:00:00Z" -i "id" # With media +postiz posts:create -c "main" -c "comment" -s "2024-12-31T12:00:00Z" -i "id" # With comment +postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" --settings '{}' -i "id" # Platform-specific +postiz posts:create --json file.json # Complex + +# Management +postiz posts:list # List posts +postiz posts:delete # Delete post +postiz upload # Upload media + +# Help +postiz --help # Show help +postiz posts:create --help # Command help +``` diff --git a/apps/cli/package.json b/apps/cli/package.json index b1c98e7f..8fb64cc4 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "postiz", - "version": "2.0.3", + "version": "2.0.5", "description": "Postiz CLI - Command line interface for the Postiz social media scheduling API", "main": "dist/index.js", "bin": { diff --git a/apps/cli/src/commands/posts.ts b/apps/cli/src/commands/posts.ts index 8131d0b9..2cc9c316 100644 --- a/apps/cli/src/commands/posts.ts +++ b/apps/cli/src/commands/posts.ts @@ -64,35 +64,24 @@ export async function createPost(args: any) { }); // Parse provider-specific settings if provided - let settings: any = { __type: 'EmptySettings' }; + // Note: __type is automatically added by the backend based on integration ID + let settings: any = undefined; if (args.settings) { try { - const parsedSettings = typeof args.settings === 'string' + settings = typeof args.settings === 'string' ? JSON.parse(args.settings) : args.settings; - - // If provider type is specified, add it to settings - if (args.providerType) { - settings = { - __type: args.providerType, - ...parsedSettings, - }; - } else { - settings = parsedSettings; - } } catch (error: any) { console.error('โŒ Failed to parse settings JSON:', error.message); process.exit(1); } - } else if (args.providerType) { - settings = { __type: args.providerType }; } // Build the proper post structure postData = { - type: args.schedule ? 'schedule' : 'now', - date: args.schedule || new Date().toISOString(), + type: args.type || 'schedule', // 'schedule' or 'draft' + date: args.date, // Required date field shortLink: args.shortLink !== false, tags: [], posts: integrations.map((integrationId: string) => ({ diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 3b410b9c..3de9dd76 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -28,11 +28,18 @@ yargs(hideBin(process.argv)) describe: 'Comma-separated list of integration IDs', type: 'string', }) - .option('schedule', { + .option('date', { alias: 's', - describe: 'Schedule date (ISO 8601 format)', + describe: 'Schedule date (ISO 8601 format) - REQUIRED', type: 'string', }) + .option('type', { + alias: 't', + describe: 'Post type: "schedule" or "draft"', + type: 'string', + choices: ['schedule', 'draft'], + default: 'schedule', + }) .option('delay', { alias: 'd', describe: 'Delay in milliseconds between comments (default: 5000)', @@ -49,13 +56,8 @@ yargs(hideBin(process.argv)) type: 'boolean', default: true, }) - .option('provider-type', { - alias: 'p', - describe: 'Provider type for settings (e.g., reddit, youtube, tiktok, x, linkedin, instagram)', - type: 'string', - }) .option('settings', { - describe: 'Provider-specific settings as JSON string', + describe: 'Platform-specific settings as JSON string', type: 'string', }) .check((argv) => { @@ -65,26 +67,33 @@ yargs(hideBin(process.argv)) if (!argv.json && !argv.integrations) { throw new Error('--integrations is required when not using --json'); } + if (!argv.json && !argv.date) { + throw new Error('--date is required when not using --json'); + } return true; }) .example( - '$0 posts:create -c "Hello World!" -i "twitter-123"', - 'Simple post' + '$0 posts:create -c "Hello World!" -s "2024-12-31T12:00:00Z" -i "twitter-123"', + 'Simple scheduled post' ) .example( - '$0 posts:create -c "Main post" -m "img1.jpg,img2.jpg" -i "twitter-123"', + '$0 posts:create -c "Draft post" -s "2024-12-31T12:00:00Z" -t draft -i "twitter-123"', + 'Create draft post' + ) + .example( + '$0 posts:create -c "Main post" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "twitter-123"', 'Post with multiple images' ) .example( - '$0 posts:create -c "Main post" -m "img1.jpg" -c "First comment" -m "img2.jpg" -c "Second comment" -m "img3.jpg,img4.jpg" -i "twitter-123"', + '$0 posts:create -c "Main post" -m "img1.jpg" -c "First comment" -m "img2.jpg" -c "Second comment" -m "img3.jpg,img4.jpg" -s "2024-12-31T12:00:00Z" -i "twitter-123"', 'Post with comments, each having their own media' ) .example( - '$0 posts:create -c "Main" -c "Comment with semicolon; see?" -c "Another!" -i "twitter-123"', + '$0 posts:create -c "Main" -c "Comment with semicolon; see?" -c "Another!" -s "2024-12-31T12:00:00Z" -i "twitter-123"', 'Comments can contain semicolons' ) .example( - '$0 posts:create -c "Thread 1/3" -c "Thread 2/3" -c "Thread 3/3" -d 2000 -i "twitter-123"', + '$0 posts:create -c "Thread 1/3" -c "Thread 2/3" -c "Thread 3/3" -d 2000 -s "2024-12-31T12:00:00Z" -i "twitter-123"', 'Twitter thread with 2s delay' ) .example( @@ -92,15 +101,15 @@ yargs(hideBin(process.argv)) 'Complex post from JSON file' ) .example( - '$0 posts:create -c "Post to subreddit" -p reddit --settings \'{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}\' -i "reddit-123"', + '$0 posts:create -c "Post to subreddit" -s "2024-12-31T12:00:00Z" --settings \'{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}\' -i "reddit-123"', 'Reddit post with specific subreddit settings' ) .example( - '$0 posts:create -c "Video description" -p youtube --settings \'{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}\' -i "youtube-123"', + '$0 posts:create -c "Video description" -s "2024-12-31T12:00:00Z" --settings \'{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}\' -i "youtube-123"', 'YouTube post with title and tags' ) .example( - '$0 posts:create -c "Tweet content" -p x --settings \'{"who_can_reply_post":"everyone"}\' -i "twitter-123"', + '$0 posts:create -c "Tweet content" -s "2024-12-31T12:00:00Z" --settings \'{"who_can_reply_post":"everyone"}\' -i "twitter-123"', 'X (Twitter) post with reply settings' ); },