Clients & integrations

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:read to discover channels and inspect publications.
  • publication:manage to 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 --json

Copy 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" --json

Use 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" --json

channels 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 --json

Inspect 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" --json

There 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" --json

Lists are paginated. When nextCursor is present, pass its value with --cursor to read the next page.

Go further

bun run postdot --help

The 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.

Was this page helpful?

On this page