Use this skill when Alex asks Hermes to manage, draft, schedule, publish, or analyze organic social media content through Postiz.
Postiz is open-source/self-hostable. The CLI package is postiz and the audited upstream agent repo was gitroomhq/postiz-agent at commit 1ba8fd4d48a8b9ee6ce1ce2dc5b3bae7bd92dfc5.
Default to draft-first operation:
-t draft) or show the exact command/JSON that would be used.schedule, deleting posts, or publishing anything live.Do not publish/schedule/delete social posts blindly from Telegram. For destructive or public-facing changes, identify the target Page/account/post ID and summarize exactly what will happen.
~/.postiz/credentials.json with mode 0600.postiz auth:status prints only the first 8 chars of a token/key, but do not paste even partial tokens into chat unless necessary.https://api.postiz.com and https://cli-auth.postiz.com) unless POSTIZ_API_URL / POSTIZ_AUTH_SERVER or stored credentials point elsewhere.POSTIZ_API_URL=https://<self-hosted-postiz-domain> and a self-hosted API key/session. Avoid hosted OAuth unless Alex intentionally chooses Postiz Cloud.~/.postiz/credentials.json into the conversation.auth:login opens a browser via xdg-open/open/start; in headless/server sessions prefer API key setup or local browser access to the Postiz web UI.npm install -g postiz@2.0.13
postiz --version
postiz auth:status
If using self-hosted Postiz, set the API URL before commands:
export POSTIZ_API_URL=https://postiz.your-domain.com
export POSTIZ_API_KEY=your_api_key_here
postiz auth:status
For persistent Hermes usage, store non-secret config and secrets safely:
POSTIZ_API_URL may go in shell profile or Hermes env.POSTIZ_API_KEY should go only in an uncommitted env file / secret store, not Git, logs, screenshots, or chat.postiz auth:status
postiz integrations:list
postiz integrations:settings <integration-id>
postiz integrations:trigger <integration-id> <method> -d '{"key":"value"}'
postiz posts:list
postiz analytics:platform <integration-id> -d 30
postiz analytics:post <post-id> -d 30
Every media file must go through postiz upload first. Do not pass local paths directly to -m or JSON image fields.
Correct:
MEDIA_URL=$(postiz upload /path/to/image-or-video | jq -r '.path')
postiz posts:create \
-c "Caption" \
-m "$MEDIA_URL" \
-s "2026-05-15T19:00:00Z" \
-t draft \
-i "<integration-id>"
Wrong:
postiz posts:create -c "Caption" -m /path/to/video.mp4 ...
Why: TikTok, Instagram, YouTube, and other providers often require publicly reachable/trusted URLs. In self-hosted Postiz this upload goes to the storage backend we configure, not to paid Postiz Cloud unless using their hosted product.
For UI/source customizations on the self-hosted instance, see references/self-hosted-ui-customization.md. Key caution: /home/avalon/apps/postiz is deployment config only; the app UI comes from the Docker image, so code changes require an explicit custom-image or upstream-patch strategy with rollback.
Known deployed instance:
references/facebook-page-oauth-and-draft-smoke.md for the Facebook Page OAuth scope-error fixes, DB/API verification commands, /api/public/v1 route gotcha, and safe draft smoke-test payload./home/avalon/apps/postizhttps://postiz.apps.poofc.com127.0.0.1:4007 -> container 5000local provider with Docker volume mounted at /uploadshttps://postiz.apps.poofc.com/uploads/...client_max_body_size 500M;DISABLE_REGISTRATION=false so Alex can create the admin user; after admin creation, set DISABLE_REGISTRATION=true in /home/avalon/apps/postiz/docker-compose.yaml and restart.https://postiz.apps.poofc.com/integrations/social/facebook; set FACEBOOK_APP_ID and FACEBOOK_APP_SECRET in the Compose env, then restart postiz.postiz.apps.poofc.com) to App domains in addition to any ads/admin hosts. If App domains only contains another host such as hermes-ads.apps.poofc.com, OAuth may fail even when the redirect URI and app secret are correct./integrations/social/facebook callback expects Redis keys like organization:<state> and login:<state> that are set by Postiz's own integration URL endpoint. Prefer the web UI or authenticated API endpoint to generate the URL.If Temporal exits with a dynamic config YAML parse error, check /home/avalon/apps/postiz/dynamicconfig/development-sql.yaml; valid content is:
system.forceSearchAttributesCacheRefreshOnRead:
- value: true
constraints: {}
https://postiz.apps.poofc.com/integrations/social/facebook.FACEBOOK_APP_ID and FACEBOOK_APP_SECRET in the Postiz environment and restart Postiz.postiz integrations:list
FACEBOOK_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="facebook" or .identifier=="facebook-page") | .id' | head -1)
postiz integrations:settings "$FACEBOOK_ID"
postiz posts:create \
-c "Draft Facebook Page post text" \
-s "2026-05-15T19:00:00Z" \
-t draft \
-i "$FACEBOOK_ID"
postiz posts:status <post-id> --status schedule
Always upload media first:
VIDEO_URL=$(postiz upload ./video.mp4 | jq -r '.path')
postiz posts:create -c "Video caption" -m "$VIDEO_URL" -s "2026-05-15T19:00:00Z" -t draft -i "<integration-id>"
For Instagram post type examples, use platform settings only after checking integrations:settings:
postiz integrations:settings <instagram-id>
postiz posts:create \
-c "Caption #hashtag" \
-m "$IMAGE_URL" \
-s "2026-05-15T19:00:00Z" \
-t draft \
--settings '{"post_type":"post"}' \
-i "<instagram-id>"
If analytics returns {"missing": true}, the platform published but did not return a usable post/content ID. Resolve with:
postiz posts:missing <post-id>
postiz posts:connect <post-id> --release-id "<platform-content-id>"
postiz analytics:post <post-id> -d 30
auth:login is self-hosted; by default it talks to Postiz's hosted auth server.docker-compose up -d postiz fails with Python Compose v1 KeyError: 'ContainerConfig' after editing environment/volumes, remove only the stale Postiz service container by compose label, then run compose up again: ids=$(sudo docker ps -aq --filter label=com.docker.compose.service=postiz); [ -n "$ids" ] && sudo docker rm -f $ids; sudo docker-compose up -d postiz.curl -I https://postiz.apps.poofc.com should usually show a 307 redirect to /auth when logged out, and docker exec postiz sh -lc 'echo "$FACEBOOK_APP_ID ${FACEBOOK_APP_SECRET:+present} $DISABLE_REGISTRATION"' confirms the Meta env without printing the secret.{"msg":"Invalid API key"}, the local organization likely has no apiKey set yet. The public API middleware checks Authorization: <org.apiKey> directly. Generate/store a private key locally, set Organization.apiKey in Postgres, then use POSTIZ_API_URL=https://postiz.apps.poofc.com and POSTIZ_API_KEY=<stored key> for CLI/API calls. Do not paste the key into chat.ads_read/ads_management are not enough for Postiz Facebook Page publishing. Postiz needs a Facebook OAuth app ID + app secret and a user/Page OAuth connection granting pages_show_list, business_management, pages_manage_posts, pages_manage_engagement, pages_read_engagement, pages_read_user_content, and read_insights. If the token debug app ID does not match the available app secret, do not configure Postiz with the wrong app./home/avalon/apps/postiz/docker-compose.yaml, treat it as a hardening issue: move them to a private env/secrets file with restrictive permissions and consider rotating the values. Never paste the values into chat/logs. On Alex's VPS the known-good remediation is: replace literal secrets in compose with ${VAR} placeholders, put actual values in /home/avalon/apps/postiz/.env with mode 0600, add .env and .postiz-api-key to .gitignore, run sudo docker-compose config -q, then sudo docker-compose up -d, and verify https://postiz.apps.poofc.com returns a 307 to /auth.FacebookProvider.maxConcurrentJob=100, InstagramProvider.maxConcurrentJob=400), so do not use Postiz as the only rate-limit safeguard; keep draft-first approval and add app-level publish caps/cooldowns where Hermes controls scheduling.~/.postiz/credentials.json.posts:delete; it is destructive.postiz upload.