Postemi API, MCP and CLI reference
This page is the complete reference for Postemi's programmable surfaces: every public REST endpoint, every command in the command-line tool, and the MCP server's tools. If you have not decided which surface you need, the developer overview is where to start.
A separate page per endpoint, with parameters and runnable examples, lives in the full documentation: postemi.com/docs/api/endpoints.
How it works
Postemi handles the same workspace as the web app, on three surfaces. The REST API from your own code, the command-line tool from the terminal and your scripts, and the MCP server from an AI agent. All three use the same permissions and limits, so what you can do on one, you can do on the others.
The REST API base URL is https://api.posty.hu/public/v1. The version is in the path, and every response is JSON.
Connecting in three steps
1. Sign up at postemi.com/app/signup. No sales call, no waiting list.
2. Connect at least one social account in the app. You cannot do this step from the API, because the platform asks a person for consent.
3. Create a key for yourself: Automations → Developers. The key is shown once, at the moment you create it.
Your first call can check that everything is in place. This endpoint responds even without a key, and tells you where to find everything:
curl https://api.posty.hu/public/v1/statusAnd your first authenticated call lists your channels:
curl https://api.posty.hu/public/v1/integrations \ -H "Authorization: psty_a_your_key"Authentication
Two kinds of credentials work. The API key is the entire Authorization header value (psty_…), and it is for your own code. The OAuth 2.1 access token (Bearer pos_…) is what you need when another application accesses Postemi on behalf of your users. The flow uses PKCE, and the metadata is machine-readable.
A key's permissions follow its owner's current role. If someone is demoted or removed from the workspace, their key immediately has only as much access as they do. If a key belongs to more than one workspace, the showorg header chooses among them.
Endpoints
Every path is under https://api.posty.hu/public/v1. The Scope column shows which scope the key needs. If it is missing, the response is 403, and it names the missing one.
| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | /status | Status and discovery. Answers without a key. | |
| POST | /signup/start | Sends a one-time code to the user's email address. Callable without a key, and gives the same answer for every address. | |
| POST | /signup/complete | With the code and the user's consent (acceptTerms: true) it creates the account and shows a full workspace key (psty_sa_) once. There is no free trial; the next step is checkout. 409 if the address already has an account. | |
| GET | /is-connected | Checks whether the key points to a valid workspace. | |
| GET | /workspaces | The workspaces the key can reach. `current` marks the one the request arrived on. If the key covers several workspaces, the other routes expect the workspace id in the `showorg` header. | |
| GET | /integrations | The connected channels: id, name, @handle, platform, and whether it can post right now. | channels:read |
| GET | /integration-settings/:id | A channel's posting rules and settings schema, with the character limit resolved for the account. | channels:read |
| POST | /integration-trigger/:id | A platform specific lookup on a channel: lists of boards, subreddits, pages. | channels:read |
| GET | /social/:integration | Returns the platform URL a person has to open to connect the channel. | channels:write |
| GET | /groups | The customer groups the channels are filed under. | channels:read |
| GET | /posts | The calendar for a period: every post with its state and time. | posts:read |
| POST | /posts | Creates a post: draft, scheduled or published now, on one or more channels. | posts:draft (posts:publish as well to publish) |
| DELETE | /posts/:id | Deletes only this one post (one channel), with its thread. The other channels of the group stay. | posts:draft |
| DELETE | /posts/group/:group | Deletes the whole group from every channel: one edit that went out to several channels. | posts:draft |
| PUT | /posts/:id/status | Moves a post between the draft and scheduled states. | posts:publish |
| GET | /posts/:id/missing | Tells you what the post still needs before it can publish. | posts:read |
| PUT | /posts/:id/release-id | Records the id and URL of a post that was published outside the platform. | posts:publish |
| GET | /find-slot/:id | The next free time slot according to the workspace's schedule. | posts:read |
| POST | /upload | Uploads an image or video to the media library, up to 1 GB. | media:write |
| POST | /upload-from-url | Pulls a media file from a public URL into the media library. | media:write |
| POST | /upload-link | A browser upload link, for when the file is on the user's device. | media:write |
| GET | /upload-link/:id | The files that arrived through an upload link, with a URL you can put in a post. | media:write |
| GET | /analytics/:integration | A channel's statistics for the requested period. | analytics:read |
| GET | /analytics/post/:postId | A published post's platform statistics. | analytics:read |
| GET | /notifications | The workspace's notifications, paginated. | posts:read |
| GET | /fotoai/status | Whether the key owner's FotoAI account is connected, as whom, and the FotoAI credit balance. | media:write |
| GET | /fotoai/models | FotoAI's image and video models with their parameters (aspect ratio, resolution, length) and credit price. | media:write |
| POST | /fotoai/quote | The exact price of a generation and a quote_id valid for 10 minutes. Spends nothing. | media:write |
| POST | /fotoai/generations | Starts a generation paid with the user's FotoAI credits, with a price ceiling (max_millicredits or quote_id) and an idempotency key. The result goes into the media library. | media:write |
| GET | /fotoai/generations | The user's recent FotoAI generations from every source, marked when one is already in this workspace's media library. | media:write |
| GET | /fotoai/generations/:id | A generation's status; once done, the images and videos saved in the media library with a URL you can put in a post. | media:write |
| POST | /fotoai/generations/:id/import | Imports any FotoAI generation (also ones made on fotoai.hu) into the media library. Importing twice returns the same media. | media:write |
| GET | /plans | The four plans (Basic, Pro, Creator, Team) with monthly and yearly prices in forints, euros, Swiss francs and US dollars, the main limits, the trial rule and the workspace's current plan. Answers without a plan gate. | |
| GET | /subscription | The state of the subscription that governs the workspace (none, trialing, active, past_due, read_only, cancelled), the plan, the period end, and any unpaid checkout started in the last hour. Ask this after payment. | |
| POST | /subscriptions/checkout | A Stripe Checkout link for the chosen plan and period. It charges nothing: the user opens the link and pays with their own Link wallet or card. Only an OAuth token or a full workspace key (psty_sa_) can call it, the payer's. | |
| GET | /subscription/portal | A short-lived link to the Stripe billing portal: plan change, cancellation, invoices, card. The same authentication rule as for checkout. |
The exact request and response schemas, field by field, are in the OpenAPI 3 description. You can generate client code from it too.
Example: a scheduled post
The date is always UTC, in ISO 8601 format. type can be draft, schedule or now.
curl -X POST https://api.posty.hu/public/v1/posts \ -H "Authorization: psty_a_your_key" \ -H "Content-Type: application/json" \ -d '{ "type": "schedule", "date": "2026-09-15T09:00:00.000Z", "shortLink": false, "posts": [{ "integration": { "id": "your_channel_id" }, "value": [{ "content": "<p>Hello everyone!</p>" }] }] }'The response returns one row per channel, with the postId you use for deletion and status changes.
Errors
Every error is JSON. In errors raised by Postemi, the msg field carries the human sentence. Calls that fail request validation get the framework's shape (statusCode, message, error). A permission 403 names the missing scope and the key owner's role, because the most common cause is not a bad key, but a demoted user.
The status code tells you whether it is worth retrying: 400, 401, 403 and 404 will not go away until you change something. 429 and 5xx will. The ApiError schema also describes all of this in a machine-readable way in the OpenAPI document.
Rate limits
Every response carries the RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (in seconds, not a timestamp) and RateLimit-Policy headers. 429 also comes with Retry-After. Every path has its own window, per key. Do not wait for the 429: you can slow down ahead of time from the remaining value.
Versioning and deprecation
The version is in the path: every public call lives under /public/v1. A breaking change would appear as a new version (/public/v2), and v1 keeps its contract. Additions happen inside v1: a new optional field, a new path, a new enumerated value. Your code should ignore fields it does not know.
If we were to deprecate a path, its response would get a Deprecation: true header, plus a Sunset header with the date after which it no longer works. That date is never less than 180 days away. Every response also carries a Link header with a rel="sunset" relation, pointing at this section. Nothing is currently being deprecated.
Command-line tool
posty-cli uses the same API, just from the terminal. Install and sign in:
npm install -g posty-cliposty auth:loginposty integrations:listSign-in opens a browser and stores the key on your machine, so you do not have to put it in your scripts. Every command can emit --json output, which is for machine processing.
| posty auth:login | Sign in through the browser. The machine stores the key. |
| posty auth:signup --email <address> | A new account with a code sent by email, without a free trial. The machine stores the key, then comes billing:subscribe. |
| posty auth:status | Which workspace this machine is linked to. |
| posty auth:logout | Delete the stored key. |
| posty integrations:list | The connected channels, with IDs. |
| posty integrations:settings <id> | A channel's rules and settings. |
| posty integrations:trigger <id> <method> | A platform-specific lookup on the channel. |
| posty posts:create -c "text" --date "..." -i "<id>" | A scheduled post to one or more channels. |
| posty posts:create -c "text" -t draft ... | The same as a draft, without publishing. |
| posty posts:create --json file.json | The full request from a file, for scripts. |
| posty posts:list | The calendar contents. |
| posty posts:delete <id> | Delete one post (one channel). |
| posty posts:delete-group <group> | Delete the whole group, from every channel. |
| posty posts:status <id> --status draft | Switch between draft and scheduled. |
| posty posts:find-slot <id> | The next free time slot. |
| posty upload <file> | Upload media to the media library. |
| posty upload:link | A browser upload link, for when the file is not on this machine. |
| posty upload:files <id> | What has arrived on the upload link. |
| posty analytics:platform <id> -d 30 | Channel statistics for the last N days. |
| posty analytics:post <id> | A post's statistics. |
| posty posts:missing <id> | What a post still needs. |
| posty fotoai:status | Whether FotoAI is connected, as whom, and the credit balance. |
| posty fotoai:models --category image | FotoAI's models with their parameters and price. |
| posty fotoai:generate -m <model> -p "prompt" --aspect 4:5 | Quote, confirm, generate with your own FotoAI credits; the result goes into the media library. |
| posty fotoai:get <id> | A generation's status and the URLs of the files saved in the media library. |
| posty billing:plans | The prices and limits of the four plans. |
| posty billing:subscribe --tier pro --period yearly | A Stripe Checkout link for the plan. --open opens it in the browser. The user pays. |
| posty billing:status | The subscription status. Check it after payment. |
| posty billing:manage | A link to the Stripe billing portal. |
MCP server
The MCP server address is https://api.posty.hu/mcp-oauth, with streamable HTTP transport and OAuth 2.1 authentication. Your agent sees these tools:
| Tool | What it does | Writes? |
|---|---|---|
| get_workspace_context | The exact time in UTC, the user's timezone and the workspace name. | no |
| list_workspaces | Lists the user's workspaces and marks the one the connection works on. | no |
| switch_workspace | Points the connection at another workspace. Every tool works there afterwards. | yes |
| list_integrations | The connected channels with id, @handle and state. | no |
| list_groups | The customer groups. | no |
| get_integration_schema | A channel's rules and the character limit resolved for the account. | no |
| get_channel_options | Platform specific choices for a channel. | yes |
| preview_post | Shows what would go out, per channel. Writes nothing. | no |
| list_posts | The calendar, in UTC and local time, with channel names. | no |
| delete_post | Deletes one unpublished post (one channel), or the whole group with allChannels: true. Refuses one that is already live. | yes |
| create_post | Draft, schedule, or publish now. | yes |
| upload_media_from_url | An image or video into the media library from a URL or a data URL. | yes |
| create_upload_link | A browser link where the user drops a file from their own computer. Lives for two hours. | yes |
| list_upload_link_files | What arrived through the upload link, with a URL you can put in a post. | no |
| fotoai_list_models | FotoAI's image and video models with parameters and credit price. | no |
| fotoai_quote | The exact price of a FotoAI generation. Spends nothing. | no |
| fotoai_generate | Generates with the user's FotoAI credits using the approved quote; the result goes into the media library. | yes |
| fotoai_get_generation | A generation's status and, once done, the URLs of the files saved in the media library, ready for a post. | yes |
| get_plans | The four plans with prices in forints, euros, Swiss francs and US dollars, the limits, the trial rule and the current plan. Only when the user asks. | no |
| subscribe | A Stripe Checkout link for the chosen plan. The user opens it and pays with their own wallet. Only on a signed in (OAuth) connection, for the owner. | yes |
| get_subscription | The subscription state and any unpaid checkout. After payment the agent uses it to confirm the plan is live. | no |
| manage_subscription | A link to the Stripe billing portal: plan change, cancellation, invoices, card. Only on an OAuth connection, for the payer. | yes |
| open_posty | Opens the Posty app: calendar, composer and channels. It is also in the ChatGPT sidebar. | no |
| open_posty_panel | The same app in the side panel of a ChatGPT conversation. Called by the app, not by the model. | no |
| read_settings | The user's settings: timezone and the workspace this connection acts on, with the values to choose from. | no |
| update_settings | Saves the timezone, or moves the connection to another workspace. The ChatGPT plugin settings call it. | yes |
| search_mentions | Channels and upcoming posts for the @ menu of the ChatGPT desktop app. Called by the app, not by the model. | no |
| get_post | One post in full (thread posts or comments, media, settings) for the editor of the Posty app. Called by the app, not by the model. | no |
| update_post | Changes a scheduled, draft or failed post from the editor of the Posty app. A published post is refused. Called by the app, not by the model. | yes |
The connection asks for authentication: without credentials the server returns 401, and the WWW-Authenticate header tells you where to request permission. This is not an error, it is the start of the flow according to the MCP standard. The tool list can still be read from the manifest.
Machine-readable
Every document an agent or a generator asks for:
- OpenAPI 3: https://posty.hu/openapi.json
- MCP manifest: https://posty.hu/.well-known/mcp.json
- Status and discovery:
https://api.posty.hu/public/v1/status - OAuth metadata:
https://api.posty.hu/.well-known/oauth-protected-resource - Short summary for agents: https://postemi.com/llms.txt
Grow your audience,not your workload
Postemi brings your social accounts together in one calendar, so you can spend more time on your leads and your business. Don't let managing your accounts take up ten hours a week.