Skip to content

HTTP API

Base URL: your Pickpost host. All bodies are JSON. The API is not versioned yet; /api/v1/... paths come with the OpenAPI document.

Send a personal API token as a Bearer token:

Authorization: Bearer pp_…

Create tokens under API & MCP in the app, or with POST /api/auth/tokens while signed in. The token is returned once and stored only as a hash. A token acts as the user who created it, in the workspace it was created in (the one open in the app at the time), and stops working if that user leaves the workspace.

A personal API token reaches the actions below (as an agent), /mcp and media uploads, nothing else: it cannot approve, invite, manage tokens, billing or the account. Anything else answers 403. Do those in the app.

Access tokens that MCP clients get from the sign-in service are not accepted here: their audience is /mcp. See MCP server.

Method and path Does
GET /api/agent/tools The action catalog: name, description, policy (Allowed or NeedsApproval), inputSchema.
POST /api/agent/tools/{action} Runs one action, for example posts.create. Body: the action’s input. Response: its output. See Tools.

GET /api/agent/tools also lists ui.setContext, which the web app uses to report which page is open. Agents do not need it.

Actions with policy NeedsApproval answer 403 ApprovalRequired here. So do edits (posts.update, posts.setVersionText, posts.setOption) of a post that is already scheduled: someone approved that post, not the change. Unschedule it in the app, or ask the user to make the change.

Method and path Does
GET /api/auth/tokens Your tokens: id, name, createdAt. Never the secret. Signed in only.
POST /api/auth/tokens Body {"name": "..."}. Response includes token, shown this once. Signed in only.

Revoke a token in the app under API & MCP.

{"code": "NotFound", "message": "Post 123 not found.", "issues": []}
code HTTP
BadInput, Invalid 400
Unauthorized 401
PlanLimit 402
ApprovalRequired, Forbidden 403
NotFound, UnknownAction 404
Conflict 409
TooManyRequests 429
Internal 500

issues is filled for Invalid: one entry per broken network limit.

PlanLimit means the workspace’s plan does not cover the request, or its monthly allowance is used up: a network outside the plan, one account too many, the month’s scheduled posts or posts on X. The message says which, and what lifts it: an upgrade, or, while paid plans are not on sale, the next month or the plan coming soon. Retrying does not help. Forbidden means the user’s role in the workspace does not allow it.

Every response carries x-request-id. Send your own X-Request-Id to have it used instead. Include it when you report a problem.

  • GET /healthz answers ok while the process runs.
  • GET /readyz answers 200 only when the database responds and the instance is not shutting down.