CLI
Drive the PostZen API from your terminal or scripts. JSON output by default, built for piping and AI agents.
The PostZen CLI wraps the full PostZen API in a single postzen command. Every command maps directly onto an API endpoint, prints JSON to stdout, and returns a meaningful exit code — so it drops cleanly into shell pipelines, cron jobs, CI, and AI agent tool calls.
The CLI is auto-generated from the same OpenAPI spec that powers the API reference and the MCP server. Its commands, flags, and types always match the API — when the spec changes, the CLI is regenerated and republished.
Install
npm install -g @postzen/cliThe CLI is a zero-dependency Node package and needs Node 20 or newer. Once installed, run postzen help for the full command list, or postzen <command> --help for details on any command.
Authenticate
Create a read-write API key on the API Keys page, then save it:
postzen auth:set --key pzn_live_...auth:set validates the key against the API before writing it to ~/.postzen/config.json (created with 0600 permissions). You can also skip the config file entirely and pass the key through the environment — useful in CI:
export POSTZEN_API_KEY=pzn_live_...The environment variable takes precedence over the saved key. Set POSTZEN_API_URL to point the CLI at a different base URL. Confirm what's in effect at any time:
postzen auth:check # verifies the resolved key against the API
postzen auth:status # shows the masked key and where it came fromYour API key is shown only once at creation — PostZen stores only a hash and can never recover it. Treat it like a password: keep it in a secret manager or environment variable and never commit it to source control.
Device authorization
Need a key without visiting the dashboard? Use the device authorization flow. POST https://api.postzen.dev/auth/cli/initiate to start a session, open the returned browserUrl in a browser and click Authorize, then poll GET https://api.postzen.dev/auth/cli/poll with the deviceCode as a bearer token (Authorization: Bearer <deviceCode>) every 5 seconds until it returns the key. The key comes back exactly once, on the first authorized poll, and the session expires after 15 minutes. See the step-by-step device authorization guide for the full flow.
JSON output
Every command prints a single compact line of JSON to stdout on success — ideal for piping into jq or feeding to an AI agent. Non-2xx responses print {"error":{...}} to stderr and exit 1; usage errors exit 2.
postzen profiles:list | jq '.profiles[].name'Add --pretty for indented, human-readable output:
postzen profiles:list --prettyCommand reference
Commands are group:action tokens. Path parameters are positional arguments; everything else is a --flag using the exact field name from the API.
| Command | Endpoint | Summary |
|---|---|---|
profiles:list | GET /v1/profiles | List profiles the key can access. |
profiles:create | POST /v1/profiles | Create a profile. |
profiles:get | GET /v1/profiles/{profileId} | Get a single profile. |
profiles:update | PUT /v1/profiles/{profileId} | Update a profile. |
profiles:delete | DELETE /v1/profiles/{profileId} | Delete a profile. |
accounts:list | GET /v1/accounts | List connected social accounts. |
accounts:disconnect | DELETE /v1/accounts/{accountId} | Disconnect an account. |
connect:create-url | GET /v1/connect/{platform} | Start an OAuth flow and return a connect URL. |
connect:complete | POST /v1/connect/{platform} | Exchange an OAuth code to finish connecting. |
media:upload <file> | POST /v1/media/presign + upload | Upload a media file and get back its public URL. |
posts:create | POST /v1/posts | Create a draft, scheduled, or immediate post. |
Examples
Schedule a post to X. Flags use the real API field names. platforms is a structured value, so it's passed as JSON; scalar lists like tags accept comma-separated values or repeated flags.
postzen posts:create \
--content "We just shipped 🚀" \
--scheduledFor "2026-08-01T09:00:00Z" \
--platforms '[{"platform":"x","accountId":"acc_123"}]' \
--tags launch,productUse --publishNow to publish immediately, or --isDraft to save a draft instead of --scheduledFor. Set exactly one of the three.
List connected accounts.
postzen accounts:list --status connectedCreate a profile.
postzen profiles:create --name "Acme Marketing" --color "#4caf50"