API and CLI
Give your tools access to the same posts you manage in Studio.
The REST API and CLI work with the same projects, posts and destinations as Studio. An agent that can run commands can prepare a draft for you; a script can use the same commands without reconstructing HTTP requests.
A dedicated MCP server and packaged agent skills are planned, not available yet. The CLI walkthrough below works from a Postdot source checkout with Bun installed. It does not require a separate CLI service or a model subscription from Postdot.
Create a draft for review
You need a running instance, permission to edit a project and a connected Bluesky channel for the example below. If needed, connect Bluesky through Studio first.
Give the integration limited access
In Studio, open Settings, then API keys. Create a key limited to your chosen project and these actions:
project:readto discover channels and inspect publications.publication:manageto create and edit drafts.
Leave publication:dispatch out. With this limited key, the integration cannot
schedule or publish. Key limits also depend on your current project role: a key
cannot grant access that its owner does not have.
Copy the secret when it is shown and store it in your agent's secret configuration or your shell environment. You can edit the key's limits or revoke it from Studio.
Keep the key out of prompts and source files
Do not paste the secret into a shared chat, commit it, or put it inside a content file.
Set POSTBOT_URL to your installation's origin, for example
http://127.0.0.1:3000 for the default local Docker installation, and
POSTBOT_API_KEY to the key secret. Run the commands below at the source checkout root.
Find your project and channel
bun run postdot projects list --jsonCopy the selected project's ID into PROJECT_ID, then inspect its channels:
export PROJECT_ID="REPLACE_WITH_PROJECT_ID"
bun run postdot channels list --project "$PROJECT_ID" --jsonUse the ID of a channel you already connected in Studio:
export CHANNEL_ID="REPLACE_WITH_CHANNEL_ID"
bun run postdot channels profile --project "$PROJECT_ID" --channel "$CHANNEL_ID" --json
bun run postdot publishers list --project "$PROJECT_ID" --jsonchannels profile describes the destination's accepted content under
active.profile. publishers list reports recorded connection state without
returning social account tokens. Neither command connects an account or publishes.
Provider authorization takes place through a human session in Studio.
Create a text-only Bluesky draft
For a built-in Bluesky channel, save this as post.json, replacing
REPLACE_WITH_CHANNEL_ID with the actual channel ID. The JSON uses the field
text required by that provider's profile; it is not a universal network payload.
{
"title": "Friday collection announcement",
"sourceContent": {
"body": {
"text": "Our new collection arrives on Friday. Take a look and tell us your favorite.",
"format": "plain_text"
},
"media": []
},
"publications": [
{
"channelId": "REPLACE_WITH_CHANNEL_ID",
"deliveryMode": "automatic",
"targetContent": {
"text": "Our new collection arrives on Friday. Take a look and tell us your favorite.",
"media": []
}
}
]
}bun run postdot posts create --project "$PROJECT_ID" --input post.json --jsonInspect the draft and review it in Studio
The response includes post.id and the created publications. Copy the destination's
publication ID to inspect it:
export PUBLICATION_ID="REPLACE_WITH_PUBLICATION_ID"
bun run postdot publications show --project "$PROJECT_ID" --publication "$PUBLICATION_ID" --jsonThere is deliberately no scheduledAt in the input. automatic selects the
channel's eventual delivery method; it does not authorize a send by itself.
The publication remains an unscheduled draft. Return to Queue in Studio to
review it, following your first publication.
For a manual message channel, use deliveryMode: "manual" and a destination payload
with body instead of text. For other networks, inspect the active profile rather
than copying Bluesky's field names. Media also has provider-specific requirements.
Inspect before repeating a write
With --json, successful commands write API JSON to standard output. Failures write
an error object to standard error and return a nonzero exit code. Requests have a
30-second deadline by default; --timeout-ms changes that deadline.
The CLI does not automatically retry writes. A transport error can mean that the server saved the draft but the response was lost. Inspect the current publications before submitting the same content again:
bun run postdot publications list --project "$PROJECT_ID" --jsonLists are paginated. When nextCursor is present, pass its value with --cursor
to read the next page.
Go further
bun run postdot --helpThe CLI also supports media upload/import, draft updates and explicit publication lifecycle commands. Those operations need the corresponding key actions. Keep a draft-only key for preparation rather than expanding its access just to make an unrelated command succeed.
The typed client is in packages/client; the REST API uses the same server-side
project and action checks. Built-in publisher OAuth and access administration
require a human session. Other clients do not bypass these boundaries.