Skip to content
API documentation

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:

shell
curl https://api.posty.hu/public/v1/status

And your first authenticated call lists your channels:

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

MethodPathWhat it doesScope
GET/statusStatus and discovery. Answers without a key.
POST/signup/startSends a one-time code to the user's email address. Callable without a key, and gives the same answer for every address.
POST/signup/completeWith 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-connectedChecks whether the key points to a valid workspace.
GET/workspacesThe 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/integrationsThe connected channels: id, name, @handle, platform, and whether it can post right now.channels:read
GET/integration-settings/:idA channel's posting rules and settings schema, with the character limit resolved for the account.channels:read
POST/integration-trigger/:idA platform specific lookup on a channel: lists of boards, subreddits, pages.channels:read
GET/social/:integrationReturns the platform URL a person has to open to connect the channel.channels:write
GET/groupsThe customer groups the channels are filed under.channels:read
GET/postsThe calendar for a period: every post with its state and time.posts:read
POST/postsCreates a post: draft, scheduled or published now, on one or more channels.posts:draft (posts:publish as well to publish)
DELETE/posts/:idDeletes only this one post (one channel), with its thread. The other channels of the group stay.posts:draft
DELETE/posts/group/:groupDeletes the whole group from every channel: one edit that went out to several channels.posts:draft
PUT/posts/:id/statusMoves a post between the draft and scheduled states.posts:publish
GET/posts/:id/missingTells you what the post still needs before it can publish.posts:read
PUT/posts/:id/release-idRecords the id and URL of a post that was published outside the platform.posts:publish
GET/find-slot/:idThe next free time slot according to the workspace's schedule.posts:read
POST/uploadUploads an image or video to the media library, up to 1 GB.media:write
POST/upload-from-urlPulls a media file from a public URL into the media library.media:write
POST/upload-linkA browser upload link, for when the file is on the user's device.media:write
GET/upload-link/:idThe files that arrived through an upload link, with a URL you can put in a post.media:write
GET/analytics/:integrationA channel's statistics for the requested period.analytics:read
GET/analytics/post/:postIdA published post's platform statistics.analytics:read
GET/notificationsThe workspace's notifications, paginated.posts:read
GET/fotoai/statusWhether the key owner's FotoAI account is connected, as whom, and the FotoAI credit balance.media:write
GET/fotoai/modelsFotoAI's image and video models with their parameters (aspect ratio, resolution, length) and credit price.media:write
POST/fotoai/quoteThe exact price of a generation and a quote_id valid for 10 minutes. Spends nothing.media:write
POST/fotoai/generationsStarts 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/generationsThe user's recent FotoAI generations from every source, marked when one is already in this workspace's media library.media:write
GET/fotoai/generations/:idA 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/importImports any FotoAI generation (also ones made on fotoai.hu) into the media library. Importing twice returns the same media.media:write
GET/plansThe 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/subscriptionThe 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/checkoutA 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/portalA 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.

shell
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:

shell
npm install -g posty-cli
posty auth:login
posty integrations:list

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

Authentication
posty auth:loginSign 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:statusWhich workspace this machine is linked to.
posty auth:logoutDelete the stored key.
Channels
posty integrations:listThe 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.
Posting
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.jsonThe full request from a file, for scripts.
Management
posty posts:listThe 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 draftSwitch 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:linkA browser upload link, for when the file is not on this machine.
posty upload:files <id>What has arrived on the upload link.
Analytics
posty analytics:platform <id> -d 30Channel statistics for the last N days.
posty analytics:post <id>A post's statistics.
posty posts:missing <id>What a post still needs.
FotoAI
posty fotoai:statusWhether FotoAI is connected, as whom, and the credit balance.
posty fotoai:models --category imageFotoAI's models with their parameters and price.
posty fotoai:generate -m <model> -p "prompt" --aspect 4:5Quote, 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.
Subscription
posty billing:plansThe prices and limits of the four plans.
posty billing:subscribe --tier pro --period yearlyA Stripe Checkout link for the plan. --open opens it in the browser. The user pays.
posty billing:statusThe subscription status. Check it after payment.
posty billing:manageA 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:

ToolWhat it doesWrites?
get_workspace_contextThe exact time in UTC, the user's timezone and the workspace name.no
list_workspacesLists the user's workspaces and marks the one the connection works on.no
switch_workspacePoints the connection at another workspace. Every tool works there afterwards.yes
list_integrationsThe connected channels with id, @handle and state.no
list_groupsThe customer groups.no
get_integration_schemaA channel's rules and the character limit resolved for the account.no
get_channel_optionsPlatform specific choices for a channel.yes
preview_postShows what would go out, per channel. Writes nothing.no
list_postsThe calendar, in UTC and local time, with channel names.no
delete_postDeletes one unpublished post (one channel), or the whole group with allChannels: true. Refuses one that is already live.yes
create_postDraft, schedule, or publish now.yes
upload_media_from_urlAn image or video into the media library from a URL or a data URL.yes
create_upload_linkA browser link where the user drops a file from their own computer. Lives for two hours.yes
list_upload_link_filesWhat arrived through the upload link, with a URL you can put in a post.no
fotoai_list_modelsFotoAI's image and video models with parameters and credit price.no
fotoai_quoteThe exact price of a FotoAI generation. Spends nothing.no
fotoai_generateGenerates with the user's FotoAI credits using the approved quote; the result goes into the media library.yes
fotoai_get_generationA generation's status and, once done, the URLs of the files saved in the media library, ready for a post.yes
get_plansThe 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
subscribeA 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_subscriptionThe subscription state and any unpaid checkout. After payment the agent uses it to confirm the plan is live.no
manage_subscriptionA link to the Stripe billing portal: plan change, cancellation, invoices, card. Only on an OAuth connection, for the payer.yes
open_postyOpens the Posty app: calendar, composer and channels. It is also in the ChatGPT sidebar.no
open_posty_panelThe same app in the side panel of a ChatGPT conversation. Called by the app, not by the model.no
read_settingsThe user's settings: timezone and the workspace this connection acts on, with the values to choose from.no
update_settingsSaves the timezone, or moves the connection to another workspace. The ChatGPT plugin settings call it.yes
search_mentionsChannels and upcoming posts for the @ menu of the ChatGPT desktop app. Called by the app, not by the model.no
get_postOne 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_postChanges 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:

Get started today

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.