# OpenPost Documentation Full Corpus > This documentation-only file is an OpenPost convenience artifact for reading the selected public documentation as one bounded corpus. > > It is not part of the llms.txt v2 proposal. Use llms.txt for the discovery index and each page's canonical URL for current source provenance. ## User guide ### Connect accounts Source: [https://openpo.st/docs/guides/accounts.md](https://openpo.st/docs/guides/accounts.md) Connect a social account before creating a post for it. In the workspace you want to use, open **Settings → Workspace → Social accounts** and choose a provider. For accounts that use provider sign-in, approve access there and return to OpenPost to select the profile, Page, or channel. #### Before you connect | Provider | Account or credential | | ---------------------------------------------------------- | -------------------------------------------------------------------- | | Bluesky | Handle and app password | | Mastodon | Public HTTPS instance, or a preconfigured instance | | Discord | Incoming webhook URL | | X, LinkedIn, Threads, Facebook, Instagram, TikTok, YouTube | Provider account and permission to publish to the chosen destination | On Hosted, OpenPost manages provider applications. If you run your own server, your administrator configures them under [self-hosting](https://openpo.st/docs/self-hosting/configuration.md). Instagram and Facebook require the account types and Page links set by Meta. TikTok and YouTube may require provider review before public posting. OpenPost shows the actions supported by your connected account and its granted permissions. Provider rules can change, so follow the reason shown beside an unavailable option. #### Turn on optional account features Select the connected account to open its details. Turn on **Analytics**, **Comments and replies**, or **Direct messages** separately if the provider and your plan support them. Some features need another provider permission. For eligible Bluesky and Mastodon accounts, **More → Find people** is also available. #### Reconnect or remove an account Use **Reconnect** if a token expired or you need to approve another permission. If several destinations share one authorization, disconnecting one leaves the others connected. Removing that authorization disconnects every destination that uses it. To revoke access at the provider too, use the provider's security settings. #### Bluesky Create an app password in **Bluesky → Settings**, then enter the handle and app password in OpenPost. Use the handle, not the account email. No server-side OAuth app is required. #### Mastodon Select a preconfigured server or enter a public HTTPS instance. Each Mastodon server can have its own app and limits. ### Analytics Source: [https://openpo.st/docs/guides/analytics.md](https://openpo.st/docs/guides/analytics.md) Use Analytics to see how an account and its posts performed over time. It includes posts you published through OpenPost and, where the provider allows it, posts published elsewhere. Those external posts appear in reports, not in **Publications**, which holds work you authored in OpenPost. #### Turn on collection for an account 1. Open **Settings → Workspace → Social accounts** and select an account. 2. Enable **Analytics** if the account supports it. If the option is unavailable, check the permissions and explanation shown beside it. 3. Open **Analytics** and allow the first collection to finish. Check the last successful update before using the figures. Disabling Analytics stops future collection for that account. It keeps the history already saved and does not disconnect the account. #### Compare the right posts Choose an account and date range. Use **All content**, **Published with OpenPost**, or **Published elsewhere** to choose which posts to compare. Follower counts describe the whole account. Views and engagement describe individual posts. Read each measurement's label. Views, impressions, and reach mean different things, and providers do not all return them. A blank measurement is not zero. If the page shows a coverage notice, the account may be newly connected, lack permission, or have only part of its provider history available. Open a content row or insight to see the posts behind it. Compare similar formats over similar periods before deciding that a topic or time worked better. #### Update or investigate missing data OpenPost collects results in the background, more often for new posts than old ones. **Refresh data** requests another collection. It may still wait for a provider limit or retry delay. If data is missing: - Check that Analytics is enabled for the selected account. - Inspect its connection status and reconnect if a required permission expired. - Check the last update and coverage notice before comparing totals. - Wait until a temporary provider limit expires, then retry the refresh. A provider may revise its numbers after publication. The latest saved result can therefore differ from an earlier report or the provider's live interface. #### Make another post from a result Choose **Repurpose** on a content item. OpenPost opens a new, unsaved composer and asks you to review the direction before requesting AI-generated copy. Check the idea, destination accounts, and final text before saving or publishing. To inspect delivery errors instead of engagement metrics, open the publication and use the [delivery troubleshooting guide](https://openpo.st/docs/guides/troubleshooting.md). ### Inbox and notifications Source: [https://openpo.st/docs/guides/inbox.md](https://openpo.st/docs/guides/inbox.md) Use **Inbox** to read and answer activity from connected accounts. Comments, direct messages, and notifications have separate controls. Turn on only the account features you need; a provider may support one without supporting another. #### Turn on comments or messages Open **Settings → Workspace → Social accounts** and select an account. Inspect **Comments and replies** and **Direct messages**, then enable each supported feature separately. If an option is unavailable, read its explanation. You may need another provider permission or a supported account type. Turning a feature off stops its future activity. Saved history stays available and the social account remains connected. #### Read and reply to comments Open the engagement list in **Inbox**. Filter by account or publication and select a comment to read its thread. Write your reply and send it. Check the delivery state. If the reply fails, read the error before retrying. Moderation actions depend on the provider. Use the actions shown for that comment to hide, delete, or respond. Use **Load older** to reach saved history beyond the first page. #### Work with direct messages Choose a conversation to read its newest saved messages. Scroll upward or choose **Load older messages** for earlier history. The selected workspace and filters determine which conversations appear. Check the conversation's provider restrictions before replying: - Facebook and Instagram enforce a customer-service reply window. OpenPost blocks sends after the stored deadline. - X requires direct-message permission for the app and connected account. - Bluesky chat requires an app-password session. - Mastodon direct posts are visible to the mentioned accounts and involved servers. They are not end-to-end encrypted. A failed reply stays visible with its status. Reconnect an expired account or fix the reported issue before retrying. Sending a direct message does not create a publication. #### Choose email notifications Open **Settings → Personal → Notifications**. For each optional event, choose **Off**, **Immediate**, or **Daily email**. Set a delivery time and timezone for the daily digest. If email delivery is unavailable, a self-hosted administrator must configure an [email provider](https://openpo.st/docs/self-hosting/email.md). In-app notifications still appear immediately. Security, access, invitation, and critical billing messages use their own delivery rules. Use a temporary **Mute** to pause optional email for every workspace or one selected workspace until a chosen time. **End now** restores your saved choices early. Muting does not disable in-app alerts or transactional messages. Notifications for a publication link to the affected result. If only one destination failed, inspect that rendition and retry it without reposting to the destinations that succeeded. ### Media library Source: [https://openpo.st/docs/guides/media-library.md](https://openpo.st/docs/guides/media-library.md) Open **Media** in the workspace that owns your files. The library keeps uploads, Image Editor designs, templates, and brand items together. Use it when you want to reuse a file in another post or find out why a file cannot be deleted. #### Find and organize files The **Assets** view contains uploaded images, video and audio, camera photos, memes, Image Editor exports, edited copies, and background-removed images. Search by name, alt text, or tag. Filter by tags, untagged files, media type, source, size, shape, or date. One file can have several tags. Selecting several tag filters shows files with all of them. Select files to tag them, mark favorites, or delete a group. Deleting a tag leaves its files in Media. Open a file to inspect its preview, size, source, alt text, tags, linked original or design, and uses. Editing an image creates a design or copy; it does not replace the original. New uploads remain untagged until you add tags. When one tag filter is active in Media or a media picker, files uploaded there can be added directly to that active tag. Composer paste and drop uploads remain untagged. OpenPost will not delete a file while a post, design, template, brand item, font, preview, or export still uses it. The file page shows each use so you can remove it first. Cleanup uses the same rules. #### Trash and automatic cleanup Post-specific temporary media moves to Trash after its final successful publication or after 14 days without use. Favorites, tags, collections, brand files, active drafts and schedules, retryable work, source relationships, and live Image Editor projects keep their media. Disk-backed Video Editor projects are separate from Media and do not keep a library file in use. Items stay in Trash for seven days before permanent removal. Restoring an item restarts its unused period. These periods cannot be changed in workspace settings. #### Choose a file in the composer Open a post's media picker and choose a source: - **Library** uses a saved file without uploading another copy. - **Upload** adds a file from your device. - **Camera** captures a still image after browser permission. - **Meme** opens OpenPost's built-in catalog, lets you fill every caption and replaceable image slot, and saves the locally rendered result in Media. - **Create** saves your post and opens [OpenPost Image Editor](https://openpo.st/docs/image-editor/index.md). OpenPost keeps files in the order you choose. It checks the file types and count against the rules for all selected accounts. If AI suggestions are configured, describe the joke and choose a tone to get several editable template and caption options. OpenPost sends only the idea and a bounded shortlist of names and written template notes to the configured model. It never sends the template images or your replaceable workspace images. Rendering stays inside OpenPost. Review the result, alt text, template source, and your right to publish the template before attaching it. Instance setup and the AI boundary are in [Environment Variables](https://openpo.st/docs/self-hosting/configuration.md). ##### Automatic alt text If your instance operator has configured OpenRouter, adding an image with no saved alt text to the text-and-thread composer asks OpenPost to draft shared alt text. The server sends a 400px JPEG thumbnail and, when present, up to 1,000 characters of the current relevant post or thread segment to OpenRouter and an eligible provider that declares it does not collect request data. OpenPost treats the text as untrusted context for better disambiguation, not as model instructions. It does not send the original image for this task. OpenPost saves the caption only while the shared alt text is still blank, so existing text and edits made while the request runs always win. Review the result and adjust it before publishing. You can also customize alt text for a specific account. A missing API key or a captioning error does not stop the image from being attached or published. The thumbnail and any relevant segment text leave the OpenPost instance for this external processing. Instance operators can review the full privacy boundary and setup in [Environment Variables](https://openpo.st/docs/self-hosting/configuration.md). #### Prepare and edit video OpenPost checks a video in your browser before upload. It keeps a compatible H.264/AAC MP4 as it is. If needed, it changes or shrinks the video to fit the selected accounts. Audio files upload directly when the active composer accepts them. The strictest size, length, file type, and shape rules apply. For one video, you can trim the start and end, preview the result, and crop it for the selected accounts. Drag the crop area or move it with the arrow keys. Use zoom to choose what stays in view. Some browsers can trim a compatible file but cannot crop it. Video changes happen in your browser. The upload view shows progress and lets you cancel. After upload, the server checks the file and makes a poster image. You cannot schedule or publish the video until this check passes. A failed check stays in Media with the error and a retry button. OpenPost then sends the video in the way each social network requires. Threads, Facebook, Instagram, and some TikTok posts download the file from a public HTTPS link. #### Storage and source files Uploads, camera photos, exports, edited copies, brand files, and custom fonts count toward the workspace storage limit. Hidden design and template previews do not count. Each edited copy keeps a link to its source file and OpenPost Image Editor page when relevant. Deleting a design does not delete its exports. You can delete an original only after nothing else uses it. Saved edited copies remain. Keep media available until posts to Threads, Facebook, Instagram, and some TikTok accounts finish. If you run OpenPost with S3 or R2, see [Media Storage](https://openpo.st/docs/self-hosting/configuration.md) for the browser upload rule. ### Media limits Source: [https://openpo.st/docs/guides/media-limits.md](https://openpo.st/docs/guides/media-limits.md) These are OpenPost's default publishing limits, generated from the same capability catalogue used by the composer, API, CLI, and MCP. They are not a promise that every connected account can publish every format. The destination preview applies account-specific limits, permissions, and provider readiness. A dash means the catalogue has no fixed limit for that field. It does not mean unlimited. Your upload plan, server configuration, provider account, and connected instance can impose lower limits. Sizes below are exact bytes; duration is in seconds. Attachment counts apply to each thread segment. #### Default limits | Destination format | Attachments | File types | Maximum bytes | Image maximum bytes | Video seconds | Additional rules | | ------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------- | ------------- | --------------------------------------------------- | | X thread | 0–4 | image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime | 536870912 | - | 140 | Video must be the only attachment | | X image post | 1–4 | image/jpeg, image/png, image/webp, image/gif | - | - | - | | | X video | 1–1 | video/mp4 | 536870912 | - | 140 | | | Bluesky thread | 0–4 | image/jpeg, image/png, image/webp, video/mp4 | 300000000 | 2000000 | 600 | Video must be the only attachment | | Bluesky images | 1–4 | image/jpeg, image/png, image/webp | - | 2000000 | - | | | Bluesky video | 1–1 | video/mp4 | 300000000 | - | 600 | | | Mastodon thread | 0–4 | image/jpeg, image/png, image/webp, image/gif, video/mp4 | - | - | - | | | Mastodon media | 1–4 | image/jpeg, image/png, image/webp, image/gif, video/mp4 | - | - | - | | | Mastodon video | 1–1 | video/mp4, video/quicktime, video/webm | 103809024 | - | - | | | Pixelfed thread | 0–4 | image/jpeg, image/png, image/webp, image/gif | - | - | - | | | Pixelfed photo | 1–4 | image/jpeg, image/png, image/webp | - | - | - | | | Pixelfed album | 2–4 | image/jpeg, image/png, image/webp | - | - | - | | | PeerTube video | 1–1 | video/mp4, video/quicktime, video/webm, video/x-matroska | - | - | - | | | Lemmy image | 1–1 | image/jpeg, image/png, image/webp, image/gif | - | - | - | | | PieFed image | 1–1 | image/jpeg, image/png, image/webp, image/gif | - | - | - | | | Threads thread | 0–10 | image/jpeg, image/png, image/webp, video/mp4, video/quicktime | - | - | - | Public HTTPS file required | | Threads media | 1–1 | image/jpeg, image/png, image/webp | - | - | - | Public HTTPS file required | | Threads carousel | 2–20 | image/jpeg, image/png, image/webp, video/mp4, video/quicktime | - | - | - | Public HTTPS file required | | Threads video | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 180 | Public HTTPS file required; Aspect ratio: 9:16, 1:1 | | LinkedIn image | 1–1 | image/jpeg, image/png, image/gif | - | - | - | | | LinkedIn document | 1–1 | application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation | 104857600 | - | - | | | LinkedIn multi-image post | 2–20 | image/jpeg, image/png, image/gif | - | - | - | | | LinkedIn video | 1–1 | video/mp4 | 524288000 | - | 1800 | | | Facebook Page photo | 1–1 | image/jpeg, image/png, image/webp | - | - | - | Public HTTPS file required | | Facebook multi-photo | 2–10 | image/jpeg, image/png, image/webp | - | - | - | Public HTTPS file required | | Facebook Page Story | 1–1 | image/jpeg, image/png, image/webp, video/mp4, video/quicktime | - | - | - | Public HTTPS file required | | Facebook Reel/video | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 180 | Public HTTPS file required; Aspect ratio: 9:16, 1:1 | | Facebook video | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 43200 | | | Instagram feed | 1–1 | image/jpeg, image/png, image/webp | - | - | - | Public HTTPS file required | | Instagram carousel | 2–10 | image/jpeg, image/png, image/webp, video/mp4, video/quicktime | - | - | - | Public HTTPS file required | | Instagram Story | 1–1 | image/jpeg, image/png, image/webp, video/mp4, video/quicktime | - | - | - | Public HTTPS file required | | Instagram Reel | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 180 | Public HTTPS file required; Aspect ratio: 9:16, 1:1 | | YouTube Short | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 180 | Aspect ratio: 9:16, 1:1 | | YouTube video | 1–1 | video/mp4, video/quicktime | 2147483648 | - | 43200 | | | TikTok video | 1–1 | video/mp4, video/quicktime, video/webm | 4294967296 | - | 600 | Public HTTPS file required; Aspect ratio: 9:16, 1:1 | | TikTok photo post | 1–35 | image/jpeg, image/webp | 20971520 | - | - | Public HTTPS file required | | Pinterest Pin | 1–1 | image/jpeg, image/png, image/webp | 20971520 | - | - | Public HTTPS file required | | Pinterest multi-image Pin | 2–5 | image/jpeg, image/png, image/webp | 20971520 | - | - | Public HTTPS file required | | Pinterest video Pin | 1–1 | video/mp4 | 2147483648 | - | 900 | | | Telegram media | 1–10 | image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime, application/pdf | - | - | - | | | Telegram video | 1–10 | image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime, application/pdf | - | - | - | | | Discord attachment | 1–10 | image/jpeg, image/png, image/webp, image/gif | 10485760 | - | - | | | Discord video | 1–1 | video/mp4, video/quicktime, video/webm | 10485760 | - | - | | #### Provider specifications and exceptions Catalogue and publisher validation reviewed: **14 September 2026**. The following API references were checked on that date: - **Bluesky:** image specifications and video schema. Images are limited to 2,000,000 bytes. MP4 video is limited to 300,000,000 bytes and 10 minutes. A segment can contain images or one video. - **X:** media upload documentation. OpenPost currently uses the legacy OAuth 1.0a upload route. Its default 512 MiB / 140-second limit is deliberate; the newer v2 route's 8 GB / 20-minute limits do not describe this adapter. Connected-account capabilities can adjust the default. A segment can contain images or one video. - **TikTok:** media transfer specifications. MP4, MOV, and WebM are supported. Direct Post uses the connected creator's available duration and privacy options. URL uploads require a verified domain and an accessible HTTPS file. - **YouTube:** video upload API. OpenPost's default file-size cap is lower than YouTube's API upload maximum. Unverified API projects can be restricted to private uploads. YouTube now supports custom Shorts thumbnails for eligible channels. OpenPost therefore does not impose a blanket Shorts restriction. - **LinkedIn:** Videos API. Video formats and account permissions differ from documents and image posts. - **Mastodon:** instance configuration. OpenPost uses the connected instance's advertised MIME types, attachment count, and image/video size limits when available. - **Pixelfed:** Mastodon-compatible statuses and media APIs. Photo and album publishing reuse the compatible transport with Pixelfed's own identity and capability reporting. The connected instance's advertised configuration wins over catalogue defaults. - **PeerTube:** REST API quick start and OpenAPI specification. Videos upload through the resumable protocol to a selected channel; transcoding state is reconciled before delivery is reported. Instance quota and transcoding policy apply. - **Lemmy:** API documentation (v3, as used by the 0.19 series). Community posts carry a required title with an optional link and body. Lemmy 1.x instances using API v4 are refused with an explicit error until a v4 adapter is certified. - **PieFed:** alpha API documentation. Community posting shares the Lemmy authoring model through PieFed's native post, community, and comment endpoints. - **Telegram:** Bot API file sending. File limits depend on the sending method and whether the deployment uses the hosted or local Bot API. The catalogue does not currently express every Telegram transfer limit. Other destinations retain their catalogue defaults. Check their current provider requirements before relying on a boundary value. OpenPost's preflight also checks analysed media, codecs, dimensions, and account restrictions that are not all shown in this table. For access or approval failures, see [connecting accounts](https://openpo.st/docs/guides/accounts.md) and the [integration setup guides](https://openpo.st/docs/self-hosting/integrations/index.md). ### Media and editors Source: [https://openpo.st/docs/guides/media.md](https://openpo.st/docs/guides/media.md) Use **Media** to keep reusable images, video, and audio for a workspace. Open it to upload a file, find an earlier upload, add tags, or see which posts and designs use a file. Switch workspaces first if a file seems to be missing. Choose a tool based on what the finished post needs: | What you want to do | Start here | | ---------------------------------------- | ---------------------------------------------------------------------- | | Find, tag, or reuse an upload | [Media library](https://openpo.st/docs/guides/media-library.md) | | Make a post image or carousel | [Image Editor](https://openpo.st/docs/image-editor/index.md) | | Combine clips, audio, text, and captions | [Video Editor](https://openpo.st/docs/video-editor/index.md) | | Remove unwanted ranges from a recording | [Quick Cut](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md#trim-with-quick-cut) | | Capture a screen, camera, or microphone | [Recorder](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md#capture-with-recorder) | #### Add the result to a post For an existing publication, start a design from its media picker. **Export and attach** can return the finished images to that post. A finished video can use **Send to OpenPost**, then **Open composer**. You can also choose saved files directly from Media. Check the preview for every destination. Providers accept different file types, sizes, and attachment counts. OpenPost keeps a file that a publication or editor still uses; open its details to check usage before deleting it. ### Create and publish Source: [https://openpo.st/docs/guides/publishing.md](https://openpo.st/docs/guides/publishing.md) Choose **New post** in the workspace where you want to publish. Select the connected accounts, then write the update you want to share. For example, you can start with one launch announcement and give its LinkedIn and X versions different openings. Each selected account gets its own destination version, called a rendition. #### Make each destination ready Open each destination in the composer and adjust its text, format, media, and provider settings. Check the preview before sending: is this the right account, does the first line make sense there, and are the files in the right order? A file or format that works for one provider may not work for another. If the composer flags a limit or required field, fix that destination before publishing. #### Save a draft or write a thread If the post needs another pass, leave it as a draft. The composer saves draft changes while you work; wait for its saved indicator, then find the post under **Publications → Drafts**. For a thread, add segments in reading order, then preview the whole sequence for each destination. #### Media Upload files in the composer or choose an existing file from [Media](https://openpo.st/docs/guides/media.md). If a video needs trimming or captions, prepare it in the Video Editor or Quick Cut, then attach the finished export. Check the media requirements shown for every selected account before you send. #### Publish Choose **Publish now** when every destination is ready, or [schedule the publication](https://openpo.st/docs/guides/scheduling.md) for later. Open the post in **Publications** and check its destination cards. A published destination can link to the post on its provider; a failed one shows a reason and, when retry is available, a **Retry** action. Fix the cause first. You do not need to resend destinations that already published. ### Quickstart Source: [https://openpo.st/docs/guides/quickstart.md](https://openpo.st/docs/guides/quickstart.md) Publish a first post and check what happened to each destination. Sign in at app.openpo.st and create a workspace. Have the social account you want to use ready. If you run your own server, finish [installation and provider setup](https://openpo.st/docs/self-hosting/index.md) first. #### 1. Connect an account Open **Settings → Workspace → Social accounts**, choose a platform, and follow its sign-in steps. Approve access to the profile, Page, or channel you want to publish to. Bluesky needs an app password instead; see [Connect accounts](https://openpo.st/docs/guides/accounts.md). #### 2. Create a publication Choose **New post** and select your connected account. Write a short update. OpenPost makes a separate version for each destination you select, so check the preview and edit any account-specific text or media before sending it. See [Create and publish](https://openpo.st/docs/guides/publishing.md) for drafts, threads, and media. #### 3. Publish or schedule Choose **Publish now** to send it, or choose a date and time and select **Schedule**. Check the timezone shown in the composer. Scheduled posts appear in **Publications → Calendar**. #### 4. Check the result Open **Publications** and select the post. Check each destination's status. **Published** means that destination was delivered. **Scheduled** means it is waiting for the time you chose. A scheduled post can pass through **Queued** and **Publishing** before delivery. If a destination shows **Failed**, open it to read the provider error. Fix the cause and retry that destination. Accounts that already succeeded do not need another post. See [Troubleshooting](https://openpo.st/docs/guides/troubleshooting.md) if the error is unclear. #### Self-hosted first run Follow the [self-hosting quickstart](https://openpo.st/docs/self-hosting/index.md), then use the same four steps. The first account created on a new instance becomes its administrator. ### Review results Source: [https://openpo.st/docs/guides/results.md](https://openpo.st/docs/guides/results.md) After publishing, open **Publications**, find the post under **Published** or **Failed**, and open it. Check each destination card: a successful one shows its delivery state and a link to the provider post when one is available. A failed one shows the delivery error and a **Retry** action when another attempt is safe. For example, if LinkedIn published but X failed, resolve the X error and retry X. Do not create a second publication to resend both. #### See responses and performance Once the post is live, open **Inbox** for comments, replies, messages, and notifications from accounts with those features enabled. Open **Analytics** to compare post and account measurements. If an account has no numbers yet, check that Analytics is enabled in its account details and allow the first collection to finish. Providers supply different measurements on different schedules, so a blank field does not by itself mean delivery failed. If you stop collecting an optional account feature later, its saved history remains available. #### Go deeper - [Analytics](https://openpo.st/docs/guides/analytics.md): enable collection, compare content, understand missing measurements, and repurpose an idea. - [Inbox and notifications](https://openpo.st/docs/guides/inbox.md): enable comments and direct messages, reply within provider limits, and set email preferences. - [Troubleshooting](https://openpo.st/docs/guides/troubleshooting.md): resolve a failed destination and retry only the work that failed. ### Schedule and calendar Source: [https://openpo.st/docs/guides/scheduling.md](https://openpo.st/docs/guides/scheduling.md) In the composer, choose **Schedule**, pick a date and time, and check the timezone shown in the dialog before saving. If the post is meant for 10:00 in another region, convert that time before you confirm. The publication stays **Scheduled** until OpenPost queues it for delivery. Open **Publications → Calendar** to check where the post landed. Use week view to inspect times or month view to see a wider plan. Open the post if you need to check its destinations or make a change. #### Delivery states The publication and its destinations can show **Scheduled**, **Queued**, **Publishing**, **Published**, or **Failed**. After delivery starts, check the post in **Publications** instead of treating its calendar slot as proof it published. One provider may succeed while another fails. Open the failed destination, read its message, correct the cause, and use **Retry** if offered. The published destinations stay published. #### Change a schedule Open a scheduled publication to change its date or time. You can also drag a scheduled item to another future slot in Calendar; the drop saves the new time. Published items cannot be moved this way. Check the new slot or reopen the post to confirm the change. If Calendar rejects the move, read its message and choose a future time. ### Troubleshooting Source: [https://openpo.st/docs/guides/troubleshooting.md](https://openpo.st/docs/guides/troubleshooting.md) Start with the error shown on the affected post or account. Note the provider, destination, and exact error text. Those details tell you whether to fix a connection, change a file, or retry delivery. #### An account will not connect 1. Sign in to the provider directly and confirm you can access the profile, Page, or channel you want to connect. 2. In OpenPost, reconnect the account and approve the requested permissions. Use the provider account that owns or manages the destination. 3. For Bluesky, use an app password. For a custom Mastodon server, use its public HTTPS address. If you use Hosted, OpenPost manages the provider app. If you self-host, also check the [provider setup guide](https://openpo.st/docs/self-hosting/integrations/index.md): the callback URL must match your public origin exactly, and the app must have the required permissions or approval. See [Connect accounts](https://openpo.st/docs/guides/accounts.md) for connection types and reconnect behavior. #### A provider rejects media - Check the destination's file type, size, duration, and attachment limits in the composer. - Preview the media and confirm you attached the finished export, not an editor project. - If the error says the provider cannot fetch a URL, check that the media is reachable over public HTTPS. A URL that works only on your local network will fail for providers that download it themselves. OpenPost may accept an upload that a particular provider cannot publish. Adjust the version for that destination or [prepare a new export](https://openpo.st/docs/guides/media.md), then retry the failed destination. #### A scheduled post did not publish Open **Publications**, select the post, and inspect the account that failed. Fix the reported permission, connection, or media problem, then retry that destination. You do not need to republish destinations that already succeeded. If the post is still **Scheduled**, it has not failed. Check its date, time, and the timezone shown in the composer before retrying anything. See [Schedule and calendar](https://openpo.st/docs/guides/scheduling.md). #### A self-hosted server is not ready From the directory containing your Compose file, check the service and recent logs: ```sh docker compose ps docker compose logs --tail=100 openpost curl -i http://localhost:8080/api/v1/ready ``` If the container is stopped, read its error in the logs. If it runs but readiness fails, check free disk space and access to the configured database and media paths. Read [configuration](https://openpo.st/docs/self-hosting/configuration.md) and [backup and recovery](https://openpo.st/docs/self-hosting/maintenance.md) before changing storage or restoring data. #### Get help If the problem remains, report an issue with the affected provider, whether you use Hosted or self-hosting, the steps that failed, and the error text. Remove tokens, passwords, and private media URLs before sharing logs or screenshots. ### Workspaces and settings Source: [https://openpo.st/docs/guides/workspaces.md](https://openpo.st/docs/guides/workspaces.md) A workspace keeps its publications, accounts, schedule, media, and members together. Choose the workspace from the switcher before you connect an account, write a post, or inspect results. The switcher marks the current workspace; if a post seems missing, check that selection first. #### Invite someone Open **Workspace settings → Members**. As an admin, enter the teammate's email, choose a role, then select **Send invite**. The page shows a link you can copy after the invitation is created. Share it directly if email delivery is unavailable. The teammate must accept the invitation before they appear as a member. Choose the role for what they need to do in this workspace: | Role | Access | | ------ | ------------------------------------ | | Admin | Manage workspace access and settings | | Editor | Create and manage workspace content | | Viewer | View workspace content and settings | Check **Invitations** to see whether the invitation is still waiting. An admin can resend or revoke it, and can change or remove a member's access later. Removing a member does not delete the workspace's publications. #### Find settings Use **Workspace settings** for members and connected accounts. Your profile menu holds personal sign-in and notification preferences. If you manage a self-hosted deployment, instance settings are separate from any one workspace. ### OpenPost documentation Source: [https://openpo.st/docs/index.md](https://openpo.st/docs/index.md) [Publish your first post Connect an account, write an update, and check that it arrived.](https://openpo.st/docs/guides/quickstart.md) [Install OpenPost on your own server](https://openpo.st/docs/self-hosting/index.md) [Connect an AI assistant](https://openpo.st/docs/mcp/index.md) [Automate OpenPost](https://openpo.st/docs/automate/index.md) [Edit a video](https://openpo.st/docs/video-editor/index.md) [Design an image](https://openpo.st/docs/image-editor/index.md) [Browse the API reference](https://openpo.st/docs/api-reference/index.md) #### Connect your accounts Choose a workspace, then [connect the profiles, Pages, or channels](https://openpo.st/docs/guides/accounts.md) you want to publish to. If someone has invited you to a workspace, its connected accounts may already be ready to use. On OpenPost Hosted, follow the connection steps in the app. On your own server, start with the [separate setup guide for your network](https://openpo.st/docs/self-hosting/integrations/index.md). Some need a developer app and approval before they can connect. #### Create and publish A **publication** keeps your post, destinations, and schedule together. Each destination gets its own version, called a **rendition**. Start with shared text and media, then adjust each account's version before sending it. - [Write a post or thread](https://openpo.st/docs/guides/publishing.md) and review each destination. - [Choose a publishing time](https://openpo.st/docs/guides/scheduling.md) and plan in Calendar. - [Upload and reuse media](https://openpo.st/docs/guides/media-library.md) across your workspace. - [Make an image](https://openpo.st/docs/image-editor/index.md), including multi-page carousels. - [Edit a video](https://openpo.st/docs/video-editor/index.md), [trim a clip, or record your screen and camera](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md). #### Check what happened Open a publication to see which destinations published and which need attention. A failed destination does not mean the others failed too. Use [Analytics](https://openpo.st/docs/guides/analytics.md) to review the results your connected accounts provide, and [Inbox](https://openpo.st/docs/guides/inbox.md) to handle supported comments and messages. Availability depends on the provider and the permissions you granted. If something went wrong, [troubleshooting](https://openpo.st/docs/guides/troubleshooting.md) helps you find the cause before retrying. #### Work with a team or automate a task [Workspace roles](https://openpo.st/docs/guides/workspaces.md) control who can view and manage your content. Use separate workspaces when accounts, media, and team access should stay apart. The [Automate section](https://openpo.st/docs/automate/index.md) has task guides for the TypeScript SDK, HTTP API, CLI, and n8n. The separate [API reference](https://openpo.st/docs/api-reference/index.md) lists every HTTP operation and schema. The [AI assistant guides](https://openpo.st/docs/mcp/index.md) explain MCP, the `openpost-cli` skill, and direct CLI use. Every interface works with the same accounts and Publications. #### Run your own instance [Install with Docker Compose](https://openpo.st/docs/self-hosting/index.md), [configure your services](https://openpo.st/docs/self-hosting/configuration.md), and [plan backups and upgrades](https://openpo.st/docs/self-hosting/maintenance.md). The self-hosting section keeps server setup separate from the guides for everyday publishing. ## Video Editor ### Browser support and recovery Source: [https://openpo.st/docs/video-editor/browser-and-recovery.md](https://openpo.st/docs/video-editor/browser-and-recovery.md) #### Supported browser Use a current desktop version of Chrome or Edge. The full editor depends on browser support for local file access, media codecs, workers, graphics, and origin-private storage. Codec, WebGPU, screen capture, hardware acceleration, and file streaming vary by browser, operating system, and device. Video Editor checks the operation you selected and explains an unavailable option. A WebM download may be available when this device cannot encode the selected MP4 settings. Editing, rendering, and transcription run on your device. OpenPost does not provide a server render or server transcription fallback. Local models can use hundreds of megabytes or more. **Models** shows their stored size and lets you remove them. #### A source is missing Reconnect the original linked file or local project folder. Cloud projects can download originals that were saved as Project Assets. A compatibility proxy or preview cache is not a replacement for the original during final export. #### A local project will not open Choose the same project folder again when the browser asks for access. Confirm that its project and media files have not been moved separately. Clearing browser data can remove remembered folder permission, even when the files are intact. #### A cloud project needs attention Open **History** and review its conflict copy. Keep the revision you intend to continue. Restoring a revision creates a new current revision instead of deleting later history. #### An export stopped Keep the tab open while rendering. After a reload, check **Exports** for the saved job and retry it. If the readiness check reports a missing source or unsupported format, fix that exact item before starting another render. #### Recording was interrupted Return to Recorder and use the recovery result it offers. Keep any verified source tracks, then add or download them. Do not clear site data while recovery files are still needed. ### Color, motion, and effects Source: [https://openpo.st/docs/video-editor/color-motion-and-effects.md](https://openpo.st/docs/video-editor/color-motion-and-effects.md) Use the dedicated workspace for the kind of change you are making. This keeps grading controls, keyframes, and the normal clip inspector from competing for the same space. #### Adjust color Open **Color**, then select the clip or sequence grade you want to change. Scopes show the balance of light and color. Primaries, wheels, and curves control the grade. You can also sample a neutral, black, or white point from the current preview frame. ![Color workspace with scopes, grade presets, color wheels, and curves](https://openpo.st/docs/assets/screenshots/video-color-light.webp) Scopes, presets, wheels, and curves in the Color workspace. Screenshot uses example media. Use **Before**, **After**, or **Split** to compare the result. Copy and paste a grade between clips, save a grade preset, or use one sequence grade when the whole edit needs the same finish. #### Animate a layer Open **Motion** to animate text, shapes, images, video, and supported effect controls. Create or open a composition, set a keyframe, move the playhead, then change the value. The Dope Sheet shows timing and the Graph view controls easing. ![Motion workspace with a composition setup beside the video preview](https://openpo.st/docs/assets/screenshots/video-motion-light.webp) The Motion workspace before adding a composition. Screenshot uses example media. Example: to slide a title in, place it off screen at the first position keyframe. Move one second forward, place it at rest, then play the range and adjust the easing. #### Add effects and transitions Open **Effects** in the left panel. Select a clip, then add a preset, or drag it onto one or more timeline clips. The inspector lets you reorder, disable, remove, reset, and keyframe supported effect parameters. You can save the current stack as your own preset. ![Effects browser with visual presets beside the preview and inspector](https://openpo.st/docs/assets/screenshots/video-effects-light.webp) The Effects browser beside the preview. Screenshot uses example media. Use an adjustment layer when one effect or grade should cover several clips below it. Add a transition only after checking the cut without it, then play the whole transition before export. ### Export and publish Source: [https://openpo.st/docs/video-editor/export-and-publish.md](https://openpo.st/docs/video-editor/export-and-publish.md) Play the full sequence, or the marked In and Out range, before exporting. Then select **Export video**. ![Export video dialog with output presets, format options, and a readiness check](https://openpo.st/docs/assets/screenshots/video-export-light.webp) Export settings and the readiness check. Screenshot uses example media. #### Check export readiness Choose an output preset, format, and quality. The readiness check reports missing sources, unsupported codecs, subtitle choices, and invalid or empty ranges before rendering starts. MP4 and WebM are the normal social-video choices. Other containers, audio-only output, and image sequences are available when the selected settings and device support them. Export reads the original sources at the chosen resolution. Keep the tab open while a render is active. A completed file appears under **Exports**. Download it and watch the finished result before publishing. If a linked source is missing, reconnect it and run the check again. #### Manage several exports The render queue can hold the whole video, marked ranges, or fixed-duration ranges. Each job keeps the timeline and settings it had when queued. The project renders one job at a time. Use **Exports** to pause, reorder, cancel, retry, or open finished work. #### Use the export in OpenPost Select **Save export to Media** to add the file to the current Workspace Media library, or **Use in a post** to open the composer with that export attached. Confirm the Workspace and destination accounts before publishing or scheduling. Project Assets do not enter Workspace Media unless you save or send an export there. If the cloud actions are unavailable, sign in and select a Workspace. You can still download the local export. ### Video Editor Source: [https://openpo.st/docs/video-editor/index.md](https://openpo.st/docs/video-editor/index.md) Open Video Editor in a current desktop version of Chrome or Edge. Choose a format, add your clips, edit on the timeline, then export the finished file. OpenPost does not add a watermark. ![Video Editor with project media, a preview, properties, and a multitrack timeline](https://openpo.st/docs/assets/screenshots/video-editor-light.webp) Project media is on the left, the preview is in the center, properties are on the right, and the timeline is below. Screenshot uses example media. #### Choose the right tool - **Video Editor** changes the picture, sound, timing, captions, motion, or effects. - **Quick Cut** keeps selected ranges without changing their picture or mix. It can avoid re-encoding when the source allows it. - **Recorder** captures your screen, camera, and microphone as synchronized files for an edit. #### Follow the editing flow 1. [Start a project](https://openpo.st/docs/video-editor/start.md) and choose where it will be saved. 2. [Import media and edit the timeline](https://openpo.st/docs/video-editor/timeline.md). 3. Adjust [color, motion, and effects](https://openpo.st/docs/video-editor/color-motion-and-effects.md). 4. Clean up [speech, captions, and audio](https://openpo.st/docs/video-editor/transcript-and-audio.md). 5. [Export the video and use it in a post](https://openpo.st/docs/video-editor/export-and-publish.md). Editing and rendering run on your device. A project saved to OpenPost syncs its authored edit and required original Project Assets to the current Workspace. A local-only project stays in a folder you choose. ### Projects and storage Source: [https://openpo.st/docs/video-editor/projects-and-storage.md](https://openpo.st/docs/video-editor/projects-and-storage.md) Video Editor supports projects saved to OpenPost and projects kept in a local folder. Both keep the edit non-destructive: trimming or applying an effect does not change the source file. #### Saved to OpenPost A cloud project belongs to the current Workspace. OpenPost syncs: - the authored project and its revisions; - original Project Assets used by the timeline; - checkpoints and conflict copies. OpenPost does not sync playhead position, panel layout, previews, downloaded models, browser file handles, or exports you have not uploaded. The editor downloads an original when it needs it. Select **Keep available offline** if this device needs the current revision and its originals without a connection. If another device changes the same project, OpenPost preserves a conflict copy instead of choosing one edit silently. Open **History** to compare revisions. Restoring an older revision creates a new current revision. Deleted cloud projects remain in Cloud Trash for 30 days. #### Local only A local project stores its work under the folder you choose. The project can contain `projects`, `media`, `recordings`, and `exports` folders for the edit, copied sources, linked-file references, previews, transcripts, render jobs, and finished files. Back up the whole folder. If the editor asks to reconnect it after a restart or permission change, choose the same folder. Clearing browser data can remove saved access to the folder and temporary caches, but it does not delete the files in that folder. You can switch folders or forget a saved folder handle without deleting its contents. If another tab has written a newer project, the editor protects the newer disk version instead of overwriting it. #### Move or share a project Importing a local project into OpenPost checks its sources and leaves the local copy in place. Only originals used by the timeline need to upload. For a portable local copy, export an `.openpost.zip` bundle. It contains the authored project and required originals. Preview caches and downloaded AI models are not included. Project Assets are separate from Workspace Media. They enter the Media library only when you save or send an export there. ### Quick Cut and Recorder Source: [https://openpo.st/docs/video-editor/quick-cut-and-recorder.md](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md) Use the focused tool when you do not need the full timeline. #### Trim with Quick Cut Open Quick Cut to keep selected ranges from a video or audio file. 1. Add one or more sources. 2. Set In and Out points. 3. Add and arrange the ranges to keep. 4. Review the export plan. 5. Download the cuts, merge compatible cuts, or send the result to OpenPost. **Nearest keyframe** can preserve encoded video and audio packets when the source permits it. **Exact time** keeps the boundary you requested and uses precise transcoding when copying cannot represent it. The preflight explains which ranges can be copied, which need encoding, and why an output is blocked. Quick Cut blocks a result that would silently drop unsupported streams. Use Video Editor instead when you need to change pixels, speed, audio levels, transitions, captions, overlays, or effects. #### Capture with Recorder Open Recorder for any supported combination of screen, camera, and microphone. Recorder keeps the sources as separate synchronized files, so you can position and mix them after capture. Choose the devices, resolution, frame rate, countdown, and planned length. Your browser remains in control of screen, camera, microphone, system-audio, and cursor permissions. Available choices vary by browser, operating system, and device. During capture, Recorder shows elapsed time, bytes written, free local space, and microphone level. It writes recoverable chunks to local scratch storage and stops before storage fills. Already written tracks remain available when a device or capture stream fails. From standalone Recorder, download each source. From Video Editor, select **Add to timeline** to import the synchronized files as one undoable edit. ### Start a project Source: [https://openpo.st/docs/video-editor/start.md](https://openpo.st/docs/video-editor/start.md) Open Video Editor, then choose **New project**. #### Choose a format Start with the format closest to where the video will be published. A vertical format suits Stories and short videos. A landscape format suits standard video posts and screen recordings. You can also enter custom dimensions. Name the project so you can find it again. The name does not become the publication text or exported filename unless you choose to reuse it. #### Choose where it is saved For signed-in users, **Saved to OpenPost** is the default. It saves the project in the current Workspace and makes the authored edit available on other devices. Choose **Local only** when the project and its sources should stay in a folder on this computer. Your browser will ask you to choose or reconnect that folder. Read [Projects and storage](https://openpo.st/docs/video-editor/projects-and-storage.md) before working offline, moving to another computer, or clearing browser data. #### Add the first source Open **Media** and select **Import media**. You can add video, audio, images, Lottie files, and supported subtitle tracks. Select an imported source to place it on the timeline. A collected local source is copied into the project. A linked source stays in its original location, so it must remain available when you edit or export. The editor checks for duplicates and prepares previews in the background. If a ProRes source cannot play directly in the browser, the editor can use a local compatibility proxy for preview. Export still reads the original. #### Learn the layout - **Media and tools** are in the left panel. - **Preview** shows the current frame and canvas controls. - **Properties** for the selection are in the right panel. - **Timeline** holds picture, sound, captions, and adjustment layers. - **Edit**, **Color**, and **Motion** switch the workspace without leaving the project. The side panels can be collapsed or docked at full height. The timeline expands into the space they leave. Panel layout, playhead position, selection, and zoom stay on this device. ### Edit on the timeline Source: [https://openpo.st/docs/video-editor/timeline.md](https://openpo.st/docs/video-editor/timeline.md) Place clips in the order you want, then play the sequence before making detailed changes. ![Video timeline with a trimmed clip, filmstrip frames, tracks, and a playhead](https://openpo.st/docs/assets/screenshots/video-timeline-detail-light.webp) A trimmed clip on the multitrack timeline. Screenshot uses example media. #### Make the basic cuts - Drag a clip edge to trim its start or end. - Move the playhead and choose **Split at playhead** to cut a clip. - Delete a selection to leave a gap. - Use **Ripple delete** to remove it and close the gap. - Set In and Out points to preview or export only part of the sequence. Example: if a recording starts with three seconds of silence, drag its left edge until speech begins. Play across the new start before continuing. #### Work with tracks Keep picture, music, voice, captions, and adjustments on separate tracks when you need to change them independently. Lock a track before editing nearby clips. Mute or solo tracks while checking the mix. Linked video and audio move together until you unlink them. The editor rejects a move when its target is locked, incompatible, or already occupied. #### Review the picture Use the source monitor to mark a useful range before adding it to the sequence. Use the program preview to check the assembled timeline. Canvas guides and snapping help position text and visual layers. Play across every cut after changing speed, a transition, or an effect. Preview uses the same effect rules as export, but the export readiness check remains the final test of codec and source support. #### Undo and use shortcuts Undo and redo cover timeline edits. Open **Editor settings** to search, change, import, export, or reset keyboard shortcuts. The editor warns when a shortcut conflicts with another command or a browser action. For repeated sections, create a nested composition. Published composition controls can expose selected text, color, number, toggle, or media values for each instance. ### Transcript, captions, and audio Source: [https://openpo.st/docs/video-editor/transcript-and-audio.md](https://openpo.st/docs/video-editor/transcript-and-audio.md) #### Transcribe speech Select a source clip and start transcription. It runs on your device. Parakeet is the default on supported WebGPU devices. Whisper Tiny, Base, Small, and Large v3 Turbo are also available. The chosen model downloads the first time you use it and remains cached until you remove it in **Models** or clear site data. ![Transcript panel ready to transcribe selected media](https://openpo.st/docs/assets/screenshots/video-transcript-light.webp) The Transcript panel before transcription. Screenshot uses example media. Read the transcript before editing from it. Correct a word to update its timed caption. Select words to stage matching media ranges, review the strikethrough, then apply the cut once. Silence and filler-word suggestions show how much time they would remove before you accept them. #### Choose the caption output Captions can be burned into the picture or exported as SRT or VTT sidecar files. A supported output container can also carry a selectable subtitle track. Review spelling, timing, and line breaks in the preview before export. #### Mix speech and music Keep voice and music on separate tracks. Lower the music under speech and add fades where it enters or leaves. Mute and solo tracks to find a problem. Loudness and ducking controls can help keep speech clear, but listen through the whole passage before export. Use **Record voiceover** to capture narration while the sequence plays. The recording becomes project media and can be trimmed like another audio clip. Transcription and voice tools depend on the browser, device, and available local storage. If a model or capture option is unavailable, the editor explains the missing requirement. ## Image Editor ### Color and effects Source: [https://openpo.st/docs/image-editor/color-and-effects.md](https://openpo.st/docs/image-editor/color-and-effects.md) Select an image layer to crop it or make a quick correction. Open **Color** when you need the same controls across a full page or want wheels, curves, scopes, and before-and-after comparison. #### Crop and adjust one image In **Properties**, open **Crop** to choose the visible part of the source. The original file remains unchanged. Use a quick look such as **Warm**, **Cool**, or **Mono**, or adjust tone and color yourself. Available controls include brightness, exposure, contrast, highlights, shadows, temperature, tint, vibrance, saturation, hue, and blur. ![Tone controls for a selected image layer](https://openpo.st/docs/assets/screenshots/image-controls-detail-light.webp) Tone controls adjust brightness, exposure, contrast, highlights, and shadows for the selected image. #### Grade a layer or page Open **Color**, then choose the scope: - **Layer** changes the selected unlocked image layers. - **Pages** changes the combined page output once, after its layers are composed. Start with a preset or the basic tone and color controls. Use Lift, Gamma, Gain, and Offset wheels for tonal ranges. Use curves for the master, red, green, or blue channel. The scopes report the current image while you work. Compare **Before** and **After**, then reset the section or the full grade if needed. #### Add layer effects Properties can apply blend modes, strokes, drop shadows, inner shadows, and shape masks. Effect controls vary by layer type. A mask changes the visible shape of an image or shape layer without changing its source. Keep effects tied to the job the design must do. Check text and logo edges at the final export size, not only while zoomed into the canvas. #### Remove an image background Select an image layer and choose **Remove background**. The feature loads only when you use it and processes the image in your browser. It uses graphics hardware when available and the processor when needed. It does not send the image to another background-removal service. ![Remove background action for a selected image layer](https://openpo.st/docs/assets/screenshots/image-background-removal-detail-light.webp) Remove background creates a transparent copy and keeps the original unchanged. The result is a new transparent PNG in Media. You can undo the layer change. OpenPost may process a smaller temporary copy for a large image without changing the original file. ### Create a design Source: [https://openpo.st/docs/image-editor/create-a-design.md](https://openpo.st/docs/image-editor/create-a-design.md) Choose the starting point that matches where the finished image needs to go. #### Start without signing in Open the public Image Editor. Pick a social format, choose a starter template, or import a PNG, JPEG, or WebP image. Public designs and imported files stay in this browser. Use the same device and browser to return to them. Clearing site data or using private browsing can remove local work. You can export at any time. To keep the editable design in a workspace, choose **Save to OpenPost** and sign in or create an account. OpenPost copies the design and its images into the selected workspace. The browser copy stays on the original device. ![Image Editor start screen with format choices and starter templates](https://openpo.st/docs/assets/screenshots/image-start-light.webp) Pick a format, a starter template, or an existing image. #### Start in a workspace Open **Media → Create → Create design**. You can also open an image in Media and choose to edit it. The original file stays unchanged, and the editor creates a separate design. Workspace designs autosave to OpenPost and can be reopened from Media. They can use workspace media, templates, brand colors, and brand fonts. #### Start from a post In a post's media picker, open **Create** and choose Image Editor. OpenPost saves the draft before leaving the composer and remembers where the finished files belong. When you are done, **Export and attach** returns the files to the same post, thread part, or thumbnail field. The editor checks the selected account limits again before attaching them. #### Choose a useful size Use a social preset when the design is for one known placement. Use custom dimensions when you already know the required pixel size. A design keeps one width and height across all its pages, so create a separate design for another aspect ratio. After the design opens, add content from Media or upload another image. Set a solid, transparent, gradient, or image page background, then add text, images, shapes, or paint layers. ### Editor layout Source: [https://openpo.st/docs/image-editor/editor-layout.md](https://openpo.st/docs/image-editor/editor-layout.md) The editor keeps one page active at a time. The canvas is the page itself. Everything placed on it is a layer. #### Desktop The desktop workspace has five main areas: 1. The top bar holds the design name, save state, undo, redo, Color, and Export. 2. The left tool rail opens media, text, shapes, paint, and other insert tools. 3. The center canvas is where you select, move, resize, rotate, crop, and preview content. 4. The right side contains **Layers** and **Properties**. 5. The page strip along the bottom selects and orders pages. Use the canvas for direct changes and the Layers or Properties panels when you need exact order, values, or controls. The panels are also the keyboard-accessible alternative to dragging on the canvas. ![Image Editor canvas with a selected logo over a photo](https://openpo.st/docs/assets/screenshots/image-canvas-detail-light.webp) Select a layer on the canvas, then use its handles or the Properties panel. #### Phone On a phone, the bottom tool rail opens one editing sheet at a time. The Layers view uses the full available height, and the page strip can collapse when you need more canvas space. You can add and transform layers, crop images, change text and shapes, reorder pages, remove backgrounds, undo, and export. Use one finger to move or transform the selected layer. Use two fingers to pan or zoom the canvas. #### Move around the canvas Use the zoom controls to fit the page or inspect detail. Panning changes only your view, not the exported design. Rulers, guides, snap lines, and safe areas help with placement but do not appear in the export. Check the save state before closing the tab. Workspace designs save to OpenPost. Public designs save to this browser. See [Saving and recovery](https://openpo.st/docs/image-editor/saving-and-recovery.md) for conflicts and browser recovery. ### Export and publish Source: [https://openpo.st/docs/image-editor/export-and-publish.md](https://openpo.st/docs/image-editor/export-and-publish.md) Choose **Export** after checking the page order, crop, text, and edges at the size you plan to publish. #### Choose what to export Export the active page or every page in order. Choose PNG, JPEG, or WebP and review the estimated total size before continuing. - A one-page download produces one image file. - A multi-page download produces a ZIP with one file per page. - Saving to Media creates separate workspace files in page order. Workspace exports in Media retain their source design and page. Editing the source later does not replace an existing export. ![Image export dialog with format, quality, size, and destination controls](https://openpo.st/docs/assets/screenshots/image-export-detail-light.webp) Choose the pages, format, quality, and destination before export. #### Return to a post When the editor was opened from a post, choose **Export and attach**. OpenPost adds the exported files in order to the same post, thread part, or thumbnail field. The return link works for two hours. The editor also keeps a local recovery copy. If it can no longer return to the post, the exported files remain in Media so you can attach them from the composer. OpenPost checks the current account limits before attaching the files. A design can export successfully even when the selected destination rejects its file count, size, or shape. Adjust the export or destination selection if that check fails. #### Publish from the composer Review the attached files in the composer. Check their order, destination-specific crop or preview, and alt text. Publishing and scheduling happen in the composer, not in Image Editor. See [Create and publish](https://openpo.st/docs/guides/publishing.md) for destination versions and [Media requirements](https://openpo.st/docs/guides/media-limits.md) for current provider limits. ### Image Editor Source: [https://openpo.st/docs/image-editor/index.md](https://openpo.st/docs/image-editor/index.md) OpenPost Image Editor makes single images and multi-page carousels. You can start without an account, work from workspace media, or open it from a post and attach the result when you finish. Open the Image Editor to start with a social format, a template, or an image. Exports have no watermark. ![Image Editor with media, canvas, layers, properties, and pages visible](https://openpo.st/docs/assets/screenshots/image-editor-light.webp) The desktop editor keeps media, the canvas, layers, properties, and pages in one workspace. #### Start - [Create a design](https://openpo.st/docs/image-editor/create-a-design.md) from a preset, template, or existing image. - [Learn the editor layout](https://openpo.st/docs/image-editor/editor-layout.md) on desktop and phone. #### Edit - [Arrange layers](https://openpo.st/docs/image-editor/layers.md) for text, images, shapes, paint, and groups. - [Build a carousel](https://openpo.st/docs/image-editor/pages-and-carousels.md) and set the page order. - [Adjust color and effects](https://openpo.st/docs/image-editor/color-and-effects.md), crop images, and remove backgrounds. - [Reuse templates and brand items](https://openpo.st/docs/image-editor/templates-and-brand.md). #### Finish - [Export or attach the result](https://openpo.st/docs/image-editor/export-and-publish.md) to a publication. - [Understand saving and recovery](https://openpo.st/docs/image-editor/saving-and-recovery.md) before changing devices or restoring an older version. - [Check the editor limits](https://openpo.st/docs/image-editor/limits.md) when a format or workflow is not available. OpenPost Image Editor edits still images. Use [Video Editor](https://openpo.st/docs/video-editor/index.md) for composed video or [Quick Cut](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md#trim-with-quick-cut) when you only need to remove parts of a compatible video. ### Layers Source: [https://openpo.st/docs/image-editor/layers.md](https://openpo.st/docs/image-editor/layers.md) Each text item, image, shape, paint stroke, or group is a layer. Layers near the top of the list appear in front of layers below them. #### Add content Use the left tool rail to add content: - **Media** adds workspace files, uploads, camera images, or stock media. It can also replace the selected image. - **Text** adds a text layer. Use Properties to set its font, size, color, alignment, spacing, and curve. - **Shapes** adds basic shapes and lines. - **Paint** draws on the active page. Drag media onto the canvas when you want to choose its placement. Clicking an item adds it with a default size. #### Select and transform Select a layer on the canvas or in **Layers**. Drag it to move it. Use the canvas handles to resize or rotate it, or enter exact position, size, rotation, and flip values in **Properties**. Select several layers to align or distribute them. Group layers when they should move and resize together. Ungroup them when you need to edit one item again. #### Change the stack Drag a layer in the Layers panel to change what covers what. Use the eye control to hide it without deleting it. Lock a layer to keep it visible while preventing accidental changes. Example: add a photo, then add a logo. Put the logo above the photo in Layers and lock the photo before positioning the logo. ![Layers panel with an image layer and reorder, hide, and lock controls](https://openpo.st/docs/assets/screenshots/image-layers-detail-light.webp) The Layers panel controls front-to-back order, visibility, and locking. #### Change the selected layer The Properties panel changes with the selected layer. Image layers expose crop and image adjustments. Text layers expose type controls. Shapes expose their fill and stroke. Common controls include opacity, position, size, rotation, blend mode, shadows, and masks. Undo and redo include layer changes. If a layer will be reused across designs, save the whole design as a template instead of copying flattened exports. ### Limits Source: [https://openpo.st/docs/image-editor/limits.md](https://openpo.st/docs/image-editor/limits.md) OpenPost Image Editor is a focused still-image editor. #### Supported work - Single-page images and designs with up to 35 ordered pages. - PNG, JPEG, and WebP imports and exports. - Solid, transparent, gradient, or image page backgrounds. - Text, image, shape, paint, and group layers. - Image crops, color adjustments, effects, masks, and background removal. - Workspace templates, brand colors, and custom fonts. - Browser-local public designs and saved workspace designs. #### Not supported Image Editor does not: - edit video or create animation; - use CMYK color or print units; - add arbitrary SVG files or remote links as layers; - mix several text styles inside one text layer; - let several people edit the same design at the same time; - expose low-level Image Editor operations through MCP. Use [Video Editor](https://openpo.st/docs/video-editor/index.md) for video, motion, audio, and captions. Use [Quick Cut](https://openpo.st/docs/video-editor/quick-cut-and-recorder.md#trim-with-quick-cut) for simple video cuts. Use a print design tool when the output requires CMYK, bleed, or physical units. #### Publication limits An exported file must still satisfy the selected social account's current limits. The composer checks file count, type, size, shape, and other provider rules before publishing. See [Media requirements](https://openpo.st/docs/guides/media-limits.md) for the rules OpenPost applies. Provider requirements can change, so the composer and connected-account readiness are authoritative for a specific post. ### Pages and carousels Source: [https://openpo.st/docs/image-editor/pages-and-carousels.md](https://openpo.st/docs/image-editor/pages-and-carousels.md) A design can contain up to 35 pages. Every page uses the same dimensions and becomes a separate image when you export the whole design. #### Add and order pages Use the page strip below the canvas: - Select a preview to edit that page. - Choose **Add page** for a blank page. - Choose **Duplicate page** when the next page should keep the same layout. - Drag page previews to change their order. - Delete a page when it should not be part of the export. The order in the page strip is the export and attachment order. ![Page strip with two pages and add, duplicate, and delete controls](https://openpo.st/docs/assets/screenshots/image-pages-detail-light.webp) Pages export from left to right in the order shown here. #### Build a carousel Start with the page that must make sense on its own, then use the middle pages for details and the last page for the next action. For a four-page launch carousel: 1. Announce the launch. 2. Show the main change. 3. Explain who it helps. 4. Give the reader one next step. Duplicate a page when repeated type, margins, or branding should stay aligned. Change only the content that needs to differ. Preview the pages in order before export. #### Keep pages consistent Each page has its own background and layers. Reuse a template when you need the same structure in another design. Use workspace brand colors and fonts for shared styling. Exporting all pages to Media keeps their order and links each exported image to its source design and page. A downloaded multi-page export is a ZIP with one image per page. ### Saving and recovery Source: [https://openpo.st/docs/image-editor/saving-and-recovery.md](https://openpo.st/docs/image-editor/saving-and-recovery.md) The save location depends on how the design started. #### Public designs Designs made without signing in stay in the current browser. Imported files stay there too. Use the same browser and device to return to the design. Private browsing, clearing site data, or removing browser storage can delete this work. Export important files or choose **Save to OpenPost** before doing any of those things. Saving to OpenPost copies the editable design and its images into a workspace. It does not remove the original browser copy. #### Workspace designs Workspace designs save soon after you stop editing. Check the save status in the top bar before closing the tab or changing devices. Changes that have not reached the server also stay in this browser for seven days. If another browser changes the same design, OpenPost does not silently overwrite it. Choose the result that matches what you need: - Reload the saved workspace version. - Save the local work as a separate copy. - Keep editing the local recovery copy until you can decide. #### Version history Open **File → Version history** for a workspace design. You can preview an earlier version or save a named version. The list shows when and by whom each version was saved, along with a summary of changes. Choose **Load more** to find older named versions. Preview a version before restoring it. OpenPost saves the current design as a restore point, then makes the selected version current. Restoring does not erase the history that came after it. #### If something looks missing Check that you are in the workspace that owns the design and its media. Reconnect to the network and wait for the save state to settle. If the editor reports a conflict, do not refresh until you have chosen whether to reload or keep the local copy. An export in Media remains a separate file even if its source design is later changed or deleted. ### Templates and brand items Source: [https://openpo.st/docs/image-editor/templates-and-brand.md](https://openpo.st/docs/image-editor/templates-and-brand.md) Templates preserve an editable layout. Brand items keep workspace colors and fonts available while you edit. #### Make a template Open a workspace design and save it as a new template. You can also replace an existing template when you intend to update that shared starting point. Starting from a template creates a separate design. Later changes to the template do not rewrite designs already created from it. Exported images are flattened files, so use the source design or template when you need to edit the layout again. Use templates for work that repeats, such as a release announcement, quote card, or carousel series. Leave content that changes as ordinary layers with clear names. #### Use the workspace brand kit Manage the brand kit in **Settings → Workspace → Brand**. It can hold: - named colors; - default page backgrounds; - whole-layer text styles; - custom WOFF2, TTF, or OTF fonts. The Image Editor exposes saved brand colors in color controls and saved fonts in text controls. Saved page backgrounds and whole-layer text styles remain in the brand kit but do not yet have direct apply actions in the editor. You must confirm that you have the right to use a custom font before uploading it. OpenPost previews the font in the browser and checks its type and size on the server. A font cannot be removed while a design or template still uses it. #### Update shared work deliberately A template or brand-kit change affects future use, not existing design content. Open the existing design and apply the new value yourself when an older design also needs the update. This keeps scheduled or previously exported work stable. Use [Version history](https://openpo.st/docs/image-editor/saving-and-recovery.md#version-history) before replacing a template or making a large layout change. ## Automate ### Authentication and workspaces Source: [https://openpo.st/docs/automate/api/authentication.md](https://openpo.st/docs/automate/api/authentication.md) Create a developer token in **Settings → Personal → Developer**. Use `api:read` for reads or `api:write` for changes. For unattended work, create one token per integration, bind it to one workspace when possible, and set an expiry. Send the token as a bearer token: ```sh curl https://app.openpo.st/api/v1/workspaces \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Accept: application/json" ``` Use an ID from the response whenever an operation asks for `workspace_id`. OpenPost checks scope and workspace access on every private request. Passing a different workspace ID does not expand a workspace-bound token. #### Store credentials - Put tokens in your platform's secret store, not in source code or command history. - Keep Hosted and self-hosted tokens separate. - Revoke a token when the integration no longer runs. - Use HTTPS for every remote instance. `401` means the bearer token is missing, invalid, expired, or revoked. `403` means the token is valid but lacks a required scope or workspace, or the requested account or plan cannot run the operation. ### HTTP API Source: [https://openpo.st/docs/automate/api/index.md](https://openpo.st/docs/automate/api/index.md) Use the HTTP API when you need raw HTTP, use a language other than JavaScript or TypeScript, or need an operation that the SDK does not cover. Hosted uses this base URL: ```text https://app.openpo.st/api/v1 ``` For self-hosting, append `/api/v1` to the public OpenPost origin. #### Start here 1. [Authenticate and select a workspace](https://openpo.st/docs/automate/api/authentication.md) 2. [Create and publish content](https://openpo.st/docs/automate/api/publications.md) 3. [Upload media](https://openpo.st/docs/automate/api/media.md) 4. [Handle revisions, retries, and jobs](https://openpo.st/docs/automate/api/reliability.md) #### Contract and reference The [API reference](https://openpo.st/docs/api-reference/index.md) is generated from the current OpenAPI contract. It lists every path, body, response, parameter, and required header. These guides explain common workflows and do not replace that reference. Download the contract from [`/openapi.json`](https://openpo.st/docs/openapi.json) to generate a client. Do not copy request or response schemas into your integration because those copies drift when the API changes. ### Media uploads Source: [https://openpo.st/docs/automate/api/media.md](https://openpo.st/docs/automate/api/media.md) Media uploads usually use three requests. Your integration creates an upload session, sends bytes to its storage target, then completes the session. If OpenPost finds identical ready media in the workspace, it returns `deduped: true` and the returned `media_id` is ready to use without the upload and completion requests. The examples use Bash, curl, and jq. #### 1. Create a session ```bash OPENPOST_BASE="https://app.openpo.st" WORKSPACE_ID="ws_..." SESSION_JSON="$(curl "$OPENPOST_BASE/api/v1/media/upload-session" \ -X POST \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: cover-2026-09-19" \ --data "$(jq -n \ --arg workspace_id "$WORKSPACE_ID" \ --arg filename "cover.png" \ --arg mime_type "image/png" \ --arg alt_text "Product import screen with the completed file list" \ '{workspace_id: $workspace_id, filename: $filename, mime_type: $mime_type, size: 48231, alt_text: $alt_text}')")" MEDIA_ID="$(printf '%s' "$SESSION_JSON" | jq -r '.media_id')" DEDUPED="$(printf '%s' "$SESSION_JSON" | jq -r '.deduped')" ``` The response includes `media_id`, `deduped`, `complete_url`, and an `upload` object with a method, URL, and headers. The following steps only run when `DEDUPED` is `false`. #### 2. Send the bytes Use the exact method and headers from `upload`. An absolute target is external storage, so do not send the OpenPost bearer token to it. A relative target is an authenticated OpenPost endpoint. ```bash if [ "$DEDUPED" = "false" ]; then UPLOAD_METHOD="$(printf '%s' "$SESSION_JSON" | jq -r '.upload.method')" UPLOAD_URL="$(printf '%s' "$SESSION_JSON" | jq -r '.upload.url')" UPLOAD_HEADERS=() while IFS= read -r header; do UPLOAD_HEADERS+=(-H "$header") done < <(printf '%s' "$SESSION_JSON" | jq -r '.upload.headers | to_entries[] | "\(.key): \(.value)"') case "$UPLOAD_URL" in http://* | https://*) UPLOAD_TARGET="$UPLOAD_URL" UPLOAD_EXTERNAL=true ;; /*) UPLOAD_TARGET="$OPENPOST_BASE$UPLOAD_URL" UPLOAD_EXTERNAL=false ;; *) printf 'Unsupported upload URL: %s\n' "$UPLOAD_URL" >&2 exit 1 ;; esac if [ "$UPLOAD_EXTERNAL" = "true" ]; then curl "$UPLOAD_TARGET" \ -X "$UPLOAD_METHOD" \ "${UPLOAD_HEADERS[@]}" \ --data-binary @cover.png else curl "$UPLOAD_TARGET" \ -X "$UPLOAD_METHOD" \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ "${UPLOAD_HEADERS[@]}" \ --data-binary @cover.png fi fi ``` #### 3. Complete the session Complete the session with the returned `media_id`, your workspace ID, and your OpenPost bearer token. Completion starts the normal validation and media-processing flow. ```bash if [ "$DEDUPED" = "false" ]; then RESULT_JSON="$(curl "$OPENPOST_BASE/api/v1/media/upload-session/$MEDIA_ID/complete" \ -X POST \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Content-Type: application/json" \ --data "{\"workspace_id\":\"$WORKSPACE_ID\"}")" MEDIA_ID="$(printf '%s' "$RESULT_JSON" | jq -r '.id')" fi ``` Use the completion response's `id` in Publication or Rendition media fields. When the create-session response is deduplicated, use its `media_id` instead and skip steps 2 and 3. The create upload session reference contains the exact request and response schemas and links to completion. JavaScript and TypeScript integrations can use [`media.upload()`](https://openpo.st/docs/automate/sdk/media.md) to run all three steps. ### Publications and Renditions Source: [https://openpo.st/docs/automate/api/publications.md](https://openpo.st/docs/automate/api/publications.md) A Publication owns the source idea, schedule, and lifecycle. A Rendition is the destination-specific version for one connected account. #### Create a draft ```sh curl https://app.openpo.st/api/v1/publications \ -X POST \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: release-2026-09-19-draft" \ --data '{ "workspace_id": "ws_...", "title": "Launch day", "content_profile": "short_text", "source_text": "The new import flow is live.", "social_account_ids": ["acc_linkedin", "acc_x"] }' ``` Creating a Publication does not publish it. Omit `social_account_ids` for a draft without destinations. Pass `social_set_id` to initialize the destination snapshot from a Social Set. The server records raw HTTP creation as `creation_source: "api"`. The TypeScript SDK sends its own client identity and records `creation_source: "sdk"` instead. #### Validate and publish Validate the saved Publication before scheduling or publishing: ```sh curl https://app.openpo.st/api/v1/publications/pub_.../validate \ -X POST \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Content-Type: application/json" \ --data '{}' ``` Send the revision from the latest Publication response when you schedule, publish, cancel, update, or replace Renditions. This example publishes immediately, so its job can be polled to completion: ```sh curl https://app.openpo.st/api/v1/publications/pub_.../publish-now \ -X POST \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: release-2026-09-19-publish" \ --data '{"expected_revision": 3}' ``` A `409` conflict means the Publication changed after revision 3. Read it again and reconcile the newer state before another write. To publish later, set `scheduled_at` to a future RFC 3339 time when you create or update the Publication, then call `/schedule` with the latest revision. Do not wait synchronously for that job: it stays pending until the scheduled time. #### Inspect each destination Read `GET /publications/{id}` after the job finishes. Check each Rendition's status, provider URL, and error fields. Use `GET /publications/{id}/events` when you need the ordered lifecycle history. Start with the create Publication reference, then use the operation list to find update bodies, Rendition fields, filters, cancellation, deletion, and failed-destination retries. ### Revisions, retries, and jobs Source: [https://openpo.st/docs/automate/api/reliability.md](https://openpo.st/docs/automate/api/reliability.md) #### Protect writes with revisions Publication responses include a `revision`. Send that value as `expected_revision` when the operation asks for it. If someone edits the Publication first, OpenPost returns `409` instead of overwriting their change. Read the current Publication after a conflict. Compare it with your intended change, then submit a new request with the current revision. #### Protect replays with idempotency keys Send a stable `Idempotency-Key` for operations that declare the header in the [API reference](https://openpo.st/docs/api-reference/index.md). Reuse the same key only when retrying the same logical request with the same input. OpenPost returns `409` when the key was already used with different input. Do not retry an uncertain mutation unless the operation supports idempotency or you first read the saved state. #### Follow durable jobs Schedule and publish responses can include a `job_id`. Poll `GET /jobs/{id}` until it reaches `completed` or `failed`, then read the Publication for each Rendition's provider result. ```sh curl https://app.openpo.st/api/v1/jobs/job_... \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Accept: application/json" ``` A successful queue response means OpenPost accepted the work. It does not mean every provider published the content. #### Handle errors by status | Status | Action | | ------ | ------------------------------------------------------------------------- | | `401` | Replace the missing, invalid, expired, or revoked token | | `403` | Check the token scope, workspace binding, account state, and plan | | `404` | Check the path, resource ID, and token visibility | | `409` | Re-read after a revision conflict, or correct an idempotency-key mismatch | | `422` | Fix the request or provider validation issues | | `429` | Honor `Retry-After` | | `5xx` | Retry safe reads with backoff; inspect state before replaying a write | Record the response's `X-Request-ID` in integration logs. It helps trace one failed request without logging credentials or full payloads. ### Command-line interface Source: [https://openpo.st/docs/automate/cli/index.md](https://openpo.st/docs/automate/cli/index.md) The `openpost` CLI controls a running Hosted or self-hosted OpenPost instance. It follows the same workspace permissions and Publication lifecycle as the web app. Use it when work starts in a terminal. For a long-running JavaScript or TypeScript service, use the [SDK](https://openpo.st/docs/automate/sdk/index.md). For a visual workflow, use [n8n](https://openpo.st/docs/automate/n8n/index.md). #### Start here 1. [Install, sign in, and choose a workspace](https://openpo.st/docs/automate/cli/setup.md) 2. [Create and publish content](https://openpo.st/docs/automate/cli/publishing.md) 3. [Run the CLI in scripts and CI](https://openpo.st/docs/automate/cli/scripts-and-ci.md) 4. [Inspect results and recover failures](https://openpo.st/docs/automate/cli/inspect-and-recover.md) Run `openpost help` or `openpost --help` when this guide and an installed version differ. The installed help describes that binary. The CLI stores `creation_source: "cli"` on Publications it creates. Publication responses expose that source alongside web, API, SDK, MCP, and automatic posting sources. ### Inspect and recover Source: [https://openpo.st/docs/automate/cli/inspect-and-recover.md](https://openpo.st/docs/automate/cli/inspect-and-recover.md) Read the saved object after every write: ```sh openpost publication view --json openpost publication events --json openpost jobs list --json ``` `scheduled`, `publishing`, and a queued job are not final provider outcomes. Inspect every Rendition. A failed Rendition includes provider error details when the provider returned them. #### Retry one destination Retry only the failed account instead of republishing successful destinations: ```sh openpost publication retry ``` Read the Publication and events again after the retry. Do not assume a successful queue response means the provider accepted the post. #### Check the instance ```sh openpost instance health openpost auth status --json openpost provider readiness --json openpost instance diagnostics --json ``` `instance diagnostics` creates a secret-safe support snapshot. Add `--deployment docker-compose`, `--provider `, or `--logs-file ` when those checks apply. #### Give the CLI to an AI agent The `openpost-cli` agent skill teaches compatible coding assistants how to inspect context, choose a command, validate the result, and read the lifecycle afterward. ```sh npx skills add https://github.com/getopenpost/openpost --skill openpost-cli ``` Use the skill when an assistant already has terminal access. Use [MCP](https://openpo.st/docs/mcp/index.md) when the assistant supports MCP and you want a direct OpenPost connection without relying on shell commands. ### Create and publish content Source: [https://openpo.st/docs/automate/cli/publishing.md](https://openpo.st/docs/automate/cli/publishing.md) #### Text posts Use `post` for short text and simple scheduled posts: ```sh openpost post create \ --content "The new import flow is live." \ --accounts x,linkedin ``` Add `--schedule "tomorrow 2pm"`, an RFC 3339 timestamp, or `--schedule next-slot`. The CLI shows the resolved time before it accepts a natural-language schedule. Omit `--accounts` to create a draft without destinations. #### Threads Separate thread segments with a line containing `---`: ```md We rebuilt the import flow. --- It now checks every row before saving. ``` ```sh openpost thread create ./thread.md --accounts x --schedule next-slot ``` #### Media and provider-specific formats `--media` accepts an existing media ID or a local file path. Repeat it for multiple attachments: ```sh openpost publication create \ --content-profile image_post \ --accounts linkedin \ --content "The new import flow is live." \ --media ./cover.png \ --media-alt "Product import screen with the completed file list" ``` Use `publication create` for link shares, carousels, stories, short video, and long video. Provider-specific flags include `--video-title`, `--video-description`, `--privacy`, `--tiktok-method`, and `--tiktok-privacy`. ```sh openpost publication create \ --content-profile long_video \ --accounts youtube \ --video-title "Import walkthrough" \ --video-description "A complete walkthrough of the new flow." \ --privacy private \ --media ./walkthrough.mp4 ``` Run `openpost provider readiness --json` before a new provider workflow. Use `openpost provider capabilities --provider --json` before choosing a content profile or provider setting. #### Validate and run the lifecycle ```sh openpost publication validate --json openpost publication schedule --at "Friday 10am" openpost publication publish-now ``` Creating a Publication never publishes it as a hidden side effect. A `--schedule` on the create command creates the draft, then schedules that saved Publication. ### Scripts and CI Source: [https://openpo.st/docs/automate/cli/scripts-and-ci.md](https://openpo.st/docs/automate/cli/scripts-and-ci.md) Use `--json` for machine-readable output. Human tables and wording may change, but JSON follows the API response shape. ```sh publication_json=$(openpost --profile ci --json post create \ --content "Build $BUILD_VERSION is ready for review." \ --accounts company-linkedin) publication_id=$(printf '%s' "$publication_json" | jq -r '.id') openpost --profile ci --json publication validate "$publication_id" ``` #### Configure an unattended profile Create a workspace-bound developer token for the job. Store it in the CI secret store, then pass configuration through environment variables: ```sh export OPENPOST_INSTANCE=https://app.openpo.st export OPENPOST_WORKSPACE=ws_... export OPENPOST_TOKEN="$CI_OPENPOST_TOKEN" openpost auth status --json openpost workspace list --json ``` The matching flags override environment variables for one command. `OPENPOST_PROFILE` selects a saved profile. #### Avoid duplicate drafts If `post create --schedule` reports that the draft was created but scheduling failed, retry the existing Publication with the command in the error. Do not rerun `post create`, because that creates another draft. Store the created Publication ID in the job output or build record. Check it before deciding whether a rerun should create new content. #### Use stdin for generated content Commands that accept `--file` also accept `-` for stdin where the command help says so: ```sh generate-release-copy | \ openpost publication create --file - --accounts company-linkedin ``` Use `--yes` only for a reviewed non-interactive command that needs confirmation. Destructive publication commands still require their explicit `--confirm` flag. ### Install and sign in Source: [https://openpo.st/docs/automate/cli/setup.md](https://openpo.st/docs/automate/cli/setup.md) #### Install Install the npm wrapper, which downloads and verifies the matching release binary: ```sh npm install -g @getopenpost/cli ``` You can also download the binary from GitHub Releases. #### Sign in Browser sign-in is the shortest path for an interactive shell: ```sh openpost auth login https://app.openpo.st ``` For a headless shell, print the verification URL and code: ```sh openpost auth login https://app.openpo.st --device ``` For CI, pass a developer token through stdin: ```sh printf '%s\n' "$OPENPOST_TOKEN" | \ openpost auth login https://app.openpo.st --with-token ``` The CLI stores named instance profiles. Use them to keep Hosted, staging, and self-hosted credentials separate: ```sh openpost instance add hosted https://app.openpo.st openpost instance use hosted openpost instance health ``` #### Select a workspace ```sh openpost workspace list openpost workspace use personal openpost account list ``` The selected workspace belongs to the active profile. You can override profile, instance, workspace, or token for one command with `--profile`, `--instance`, `--workspace`, or `--token`. Connect new social accounts in the web app at `/settings?tab=accounts`. The CLI does not collect provider credentials. ### Automate Source: [https://openpo.st/docs/automate/index.md](https://openpo.st/docs/automate/index.md) Choose the interface that fits where the work starts. Every option uses the same OpenPost accounts, workspaces, Publications, provider checks, and publishing jobs. | Start here | Use when | | --------------------------------------- | ----------------------------------------------------------------------- | | [TypeScript SDK](https://openpo.st/docs/automate/sdk/index.md) | You are writing JavaScript or TypeScript for Node.js, Bun, or Workers | | [HTTP API](https://openpo.st/docs/automate/api/index.md) | You need raw HTTP or are using another programming language | | [Command-line interface](https://openpo.st/docs/automate/cli/index.md) | The work starts in a shell, script, CI job, or terminal-capable agent | | [n8n workflows](https://openpo.st/docs/automate/n8n/index.md) | You want a visual workflow started by a timer, webhook, or another node | | [AI assistants](https://openpo.st/docs/mcp/index.md) | You want ChatGPT, Claude, Cursor, or another assistant to use OpenPost | #### Keep automation predictable Create, validate, schedule, and publish are separate steps. Creating a Publication does not publish it. Validate before scheduling or publishing, then inspect the Publication and its Renditions for the final provider result. For unattended work, create a separate developer token for each integration. Give it only the scope it needs, bind it to one workspace when possible, set an expiry, and store it in the integration's secret store. #### Start with a read Whichever interface you choose, begin by listing the workspaces the credential can access. Select the intended workspace before creating content. This catches the most common setup errors without changing anything. When a workflow writes, start by creating an unpublished draft. Add scheduling or publishing only after the draft appears in **Publications** with the expected accounts, text, media, and provider settings. #### Build for retries Publishing can continue in a background job. Store returned Publication and job IDs, and read the current state instead of treating a successful request as proof that every provider published the content. Use the revision you last read when an operation asks for one. A conflict means someone changed the Publication. Read it again and reconcile the new version before retrying. The [API reference](https://openpo.st/docs/api-reference/index.md) remains the source for every HTTP operation and schema. The guides in this section explain common workflows and decisions. ### Build a publishing workflow Source: [https://openpo.st/docs/automate/n8n/build-a-workflow.md](https://openpo.st/docs/automate/n8n/build-a-workflow.md) Build the workflow in explicit steps. Creating a Publication does not schedule or publish it. #### 1. Start with input Use a Schedule Trigger for a recurring workflow, a Webhook for event-driven input, or another node that returns content. Keep one intended Publication per input item. #### 2. Create a draft Add an OpenPost node and choose **Publication → Create**. Map the workspace, internal title, content profile, source text, and destination accounts from the incoming item. For the first run, leave the draft unpublished. Open it in **Publications** and check the accounts, text, media, and provider settings. The package includes a `create-draft` example. Replace its placeholder workspace and account IDs before running it. #### 3. Validate Add **Publication → Validate** with the created Publication ID. Stop the workflow or route the item for review when validation returns issues. Provider readiness and destination settings can change. Validation at publish time is still required even when an earlier draft was valid. #### 4. Schedule or publish Add **Publication → Schedule** or **Publication → Publish Now**. Pass the revision returned by the latest create, update, or Set Renditions action. Scheduling uses the saved `scheduled_at`. Use **Posting Schedule → Get Next Available Slot** before an update when the workflow should use a workspace slot. #### 5. Verify the result When the lifecycle action returns a job ID, use **Job → Get** until the job reaches a final state. Then use **Publication → Get** or **Publication → Get Events** to inspect each Rendition. Keep the Publication and job IDs in workflow output. A queued action is not proof that every provider published the content. ### n8n workflows Source: [https://openpo.st/docs/automate/n8n/index.md](https://openpo.st/docs/automate/n8n/index.md) Use `@getopenpost/n8n-nodes-openpost` when a timer, webhook, form, database, or another n8n node should create OpenPost content. The node calls the normal OpenPost API and follows the same workspace and Publication lifecycle rules as the web app. The package requires Node.js 22.22 or newer in the n8n runtime. Its version is independent from the OpenPost app version. #### Start here 1. [Install the node and create credentials](https://openpo.st/docs/automate/n8n/setup.md) 2. [Build a draft-to-publish workflow](https://openpo.st/docs/automate/n8n/build-a-workflow.md) 3. [Upload n8n binary data](https://openpo.st/docs/automate/n8n/media.md) 4. [Handle retries and failures](https://openpo.st/docs/automate/n8n/reliability.md) #### Available work The node can list workspaces and accounts, check provider readiness, resolve Social Sets, find the next posting slot, upload media, manage the Publication lifecycle, read lifecycle events, and inspect jobs. This package does not include an OpenPost trigger. Start with n8n's Schedule Trigger, Webhook, or another trigger. OpenPost-specific triggers will depend on the generic event and webhook API rather than an n8n-only endpoint. ### Upload binary data Source: [https://openpo.st/docs/automate/n8n/media.md](https://openpo.st/docs/automate/n8n/media.md) Use **Media → Upload Binary** when an earlier n8n node returns an image or video as binary data. 1. Select the OpenPost workspace. 2. Set the binary property name, such as `data`. 3. Add alt text for visual media when the upstream source does not supply it. 4. Run the node and keep the returned media ID. 5. Map that ID into the Publication or Rendition media field. The node runs the full OpenPost upload-session flow. It creates the media record, uploads bytes to the returned storage target, and completes the session through authenticated OpenPost REST. The OpenPost bearer token is never sent to an external storage upload URL. The node sends only the headers returned for that upload target. OpenPost still checks workspace quotas, MIME type, file size, media processing, and provider limits. A successful byte upload can still require processing before the item is ready to publish. Use **Media → Get Many** when the workflow should select an existing library item instead of uploading another copy. ### Retries and failures Source: [https://openpo.st/docs/automate/n8n/reliability.md](https://openpo.st/docs/automate/n8n/reliability.md) #### Idempotency keys Write actions send an `Idempotency-Key`. When you leave the field blank, the node derives a key from the n8n execution ID, action, and input item index. Keep the same key only when retrying the same logical action with the same input. A different payload with a reused key can return a conflict. #### Automatic retries The node retries transient network failures and `429`, `502`, `503`, and `504` responses for reads. It retries a write only when the action has an idempotency key. Revision conflicts are not transient. Read the Publication again and decide whether to keep the user's change, apply the workflow's change, or stop for review. #### Multiple items The OpenPost node preserves n8n item linking. An output item stays connected to the input item that produced it. Enable continue-on-fail only when later nodes can distinguish error items and handle them safely. #### Diagnose a failed item Errors include the OpenPost `X-Request-ID` when the server returns one. Store that ID with the n8n execution ID. Do not log the OpenPost token or full credential object. For a publishing failure: 1. Read the job if the action returned a job ID. 2. Read the Publication and its Renditions. 3. Read Publication events for the provider error and attempt history. 4. Use **Retry Failed Renditions** only after fixing the reported issue. Do not rerun the whole workflow when it would create a second draft. Resume from the saved Publication ID. ### Install and connect Source: [https://openpo.st/docs/automate/n8n/setup.md](https://openpo.st/docs/automate/n8n/setup.md) #### Install the node In n8n, open **Settings → Community nodes**, select **Install**, and enter: ```text @getopenpost/n8n-nodes-openpost ``` Your n8n runtime must use Node.js 22.22 or newer. #### Create an OpenPost credential Create a developer token in OpenPost under **Settings → Personal → Developer**. Use a workspace-bound `api:write` token for a workflow that creates or changes content. Name the token after the n8n workflow or instance so it is easy to revoke later. Add an **OpenPost API** credential in n8n: - **Base URL:** `https://app.openpo.st`, or the public origin of your self-hosted instance. Do not append `/api` or `/api/v1`. - **API Token:** the OpenPost developer token. If n8n runs in Docker, `localhost` means the n8n container. Use the OpenPost Compose service name when both services share a network, or `host.docker.internal` when OpenPost runs on the host. #### Test access Import the package's `list-workspaces` example, select the OpenPost credential, and run it. The returned items show which workspaces the token can access. Do this read-only check before adding write actions. A workspace-bound token cannot write to another workspace even when a node receives its ID from earlier input. ### TypeScript SDK Source: [https://openpo.st/docs/automate/sdk/index.md](https://openpo.st/docs/automate/sdk/index.md) Use `@getopenpost/sdk` for JavaScript or TypeScript services, scripts, and CI jobs. It runs on Node.js 20 or newer, Bun, and Cloudflare Workers. It has no runtime dependencies and uses the platform `fetch` implementation. The SDK covers workspaces, accounts, Social Sets, Publications, Renditions, media, and jobs. Use the [HTTP API](https://openpo.st/docs/automate/api/index.md) when another language or an operation outside the SDK is a better fit. #### Start here 1. [Install and connect](https://openpo.st/docs/automate/sdk/setup.md) 2. [Create and publish content](https://openpo.st/docs/automate/sdk/publications.md) 3. [Upload media](https://openpo.st/docs/automate/sdk/media.md) 4. [Handle jobs, conflicts, and errors](https://openpo.st/docs/automate/sdk/reliability.md) #### Good uses - Turn a product event into a draft from an application backend. - Prepare account-specific Renditions before a release. - Upload generated images or video and attach their media IDs. - Schedule content from a CI job, then wait for the durable job result. Publications created through this package store and return `creation_source: "sdk"`. This distinguishes SDK-created records from raw API, CLI, MCP, web, and automatic posting. ### Upload media Source: [https://openpo.st/docs/automate/sdk/media.md](https://openpo.st/docs/automate/sdk/media.md) `media.upload()` handles the OpenPost upload-session flow. It reserves the media record, sends the bytes to the returned storage target, and completes the record. ```ts const bytes = new Uint8Array(await Bun.file("cover.png").arrayBuffer()); const asset = await openpost.media.upload({ workspaceId: openpost.workspaceId(), file: bytes, filename: "cover.png", mimeType: "image/png", altText: "Product import screen with the completed file list", }); ``` External storage targets receive only the upload headers returned by OpenPost. The SDK never sends your OpenPost bearer token to another origin. Attach the returned ID when you create a Publication: ```ts const draft = await openpost.publications.create({ workspace_id: openpost.workspaceId(), title: "Import walkthrough", content_profile: "image_post", source_text: "The new import flow is live.", social_account_ids: ["acc_linkedin"], media: [ { media_id: asset.id, alt_text: "Product import screen with the completed file list", }, ], }); ``` Use `media.list(workspaceId)` to inspect the library and `media.remove(id)` to remove an unused item. OpenPost still applies workspace quotas, file validation, provider limits, and media processing after the bytes arrive. ### Publications and Renditions Source: [https://openpo.st/docs/automate/sdk/publications.md](https://openpo.st/docs/automate/sdk/publications.md) A Publication owns the source idea and lifecycle. A Rendition is the version for one connected account. Create a draft first, inspect it, then validate and schedule or publish it. #### Create a draft ```ts const draft = await openpost.publications.create({ workspace_id: openpost.workspaceId(), title: "Launch day", content_profile: "short_text", source_text: "We just shipped the new import flow.", social_account_ids: ["acc_linkedin", "acc_x"], }); ``` Omit `social_account_ids` to keep the draft without destinations. Pass `social_set_id` to copy that Social Set's accounts and saved destination defaults into the new Publication. #### Customize a destination Read the current revision before changing Renditions. Send every Rendition you want to keep because this method replaces the saved destination set. ```ts const linkedinOptions = await openpost.accounts.destinationOptions("acc_linkedin"); console.dir(linkedinOptions, { depth: null }); const saved = await openpost.publications.upsertRenditions(draft.id, draft.revision, [ { social_account_id: "acc_linkedin", body: "We shipped a faster import flow. Read the release notes:", settings: { url: "https://example.com/releases/imports" }, }, { social_account_id: "acc_x", body: "The new import flow is live.", }, ]); ``` Resolve `accounts.destinationOptions(accountId)` before constructing provider-specific settings. It returns the current keys and choices for that account. OpenPost returns a conflict when an account has multiple subdestinations and the Rendition does not include a `target_key`. #### Validate and publish now ```ts await openpost.publications.validate(saved.id, { throwOnInvalid: true }); const action = await openpost.publications.publishNow(saved.id, saved.revision); if (action.job_id) { await openpost.jobs.wait(action.job_id); } ``` To publish later, set `scheduled_at` with `create()` or `update()`, then call `schedule()` with the latest revision. A scheduled job remains pending until that time, so do not call `jobs.wait()` in a short-lived request. `publishNow`, `schedule`, `cancel`, and `remove` take the revision you last read. This prevents a stale process from overwriting a newer edit. `retryFailed` retries failed Renditions without republishing successful ones. #### Read the outcome ```ts const result = await openpost.publications.wait(saved.id, { timeoutMs: 120_000, intervalMs: 2_000, }); for (const rendition of result.renditions) { console.log(rendition.platform, rendition.status, rendition.external_url); } ``` Do not treat a queued job as proof of provider delivery. Read the final Publication, its Renditions, or `publications.events(id)`. ### Jobs, conflicts, and errors Source: [https://openpo.st/docs/automate/sdk/reliability.md](https://openpo.st/docs/automate/sdk/reliability.md) Publishing runs in durable jobs. Store the returned Publication ID and `job_id` so a later process can resume inspection without creating the content again. ```ts const action = await openpost.publications.publishNow(publication.id, publication.revision); if (action.job_id) { const job = await openpost.jobs.wait(action.job_id); console.log(job.status); } ``` `jobs.wait()` throws `operation_failed` when the job reaches a failed state. It does not rerun the action that created the job. #### Handle typed errors ```ts import { OpenPostError } from "@getopenpost/sdk"; try { await openpost.publications.schedule(id, revision); } catch (error) { if (error instanceof OpenPostError && error.code === "conflict") { const current = await openpost.publications.get(id); // Compare current with the intended change before trying again. } if (error instanceof OpenPostError && error.code === "rate_limited") { await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 1_000)); } } ``` | Code | Action | | ------------------ | ------------------------------------------------------------- | | `missing_config` | Set the token, workspace, or instance | | `unauthorized` | Replace an invalid, expired, or revoked token | | `forbidden` | Check token scope, workspace binding, plan, and account state | | `conflict` | Read the Publication again and reconcile its revision | | `validation` | Fix the request or provider validation issues | | `rate_limited` | Wait for `retryAfterMs` | | `operation_failed` | Inspect the job and Publication events | The SDK retries one failed `GET` for `429` and server errors. It does not retry mutations because not every write operation is idempotent. Decide whether to replay a mutation only after reading the saved object. ### Install and connect Source: [https://openpo.st/docs/automate/sdk/setup.md](https://openpo.st/docs/automate/sdk/setup.md) #### Install ```sh npm install @getopenpost/sdk ``` Create a developer token in **Settings → Personal → Developer**. For an unattended service, create a separate token, give it only the scopes it needs, bind it to one workspace when possible, and set an expiry. #### Configure the client ```ts import { OpenPost } from "@getopenpost/sdk"; const openpost = new OpenPost({ token: process.env.OPENPOST_TOKEN, workspaceId: process.env.OPENPOST_WORKSPACE_ID, }); ``` The default origin is `https://app.openpo.st`. For self-hosting, set `baseUrl` to the OpenPost origin, without `/api/v1`: ```ts const openpost = new OpenPost({ baseUrl: "https://social.example.com", token: process.env.OPENPOST_TOKEN, workspaceId: process.env.OPENPOST_WORKSPACE_ID, }); ``` You can use environment variables instead of constructor options: | Variable | Purpose | | ----------------------- | -------------------------------------------- | | `OPENPOST_TOKEN` | Developer token | | `OPENPOST_URL` | OpenPost origin | | `OPENPOST_INSTANCE` | Fallback name for the OpenPost origin | | `OPENPOST_WORKSPACE_ID` | Default workspace ID | | `OPENPOST_WORKSPACE` | Fallback workspace value shared with the CLI | The SDK rejects credentialed plain HTTP by default. For a local self-hosted instance, pass `allowInsecureHttp: true` only when you control the network. #### Test access ```ts const workspaces = await openpost.workspaces.list(); console.log(workspaces.map(({ id, name }) => ({ id, name }))); ``` Use an ID from this response as `workspaceId`. A workspace-bound token cannot access another workspace even if code passes its ID. ## AI assistants ### Connect Antigravity Source: [https://openpo.st/docs/mcp/antigravity.md](https://openpo.st/docs/mcp/antigravity.md) Use OpenPost's local MCP bridge with Antigravity. This works with Hosted or a self-hosted instance that your computer can reach, and avoids differences in remote authentication between Antigravity surfaces. #### Install and authenticate Follow [the local bridge setup](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md) to install `openpost-mcp` and sign in with the `local` profile. Use your Hosted or self-hosted origin during login. #### Add the MCP configuration Open Antigravity's MCP configuration through **Settings → Customizations → Open MCP Config**, or **MCP Servers → Manage → View raw config** in the IDE. Merge: ```json { "mcpServers": { "openpost": { "command": "openpost-mcp", "args": ["--profile", "local"] } } } ``` Use the full path from `command -v openpost-mcp` if Antigravity cannot find the command. Save and refresh the MCP servers or restart the app. #### Check the connection Ask, "List my OpenPost workspaces," then name one and request its schedule without making changes. If authentication fails, sign in again with the same profile. The bridge must run as the user who saved those credentials. See Google's Antigravity setup guide for the MCP configuration controls. ### Connect ChatGPT Source: [https://openpo.st/docs/mcp/chatgpt.md](https://openpo.st/docs/mcp/chatgpt.md) You can connect OpenPost's remote MCP server in ChatGPT developer mode. Your account and workspace policy determine whether developer mode and custom connections are available. Start with read access to check the connection, then grant write access if you want ChatGPT to prepare or publish content. #### Add OpenPost 1. In ChatGPT, open **Settings → Security and login** and turn on **Developer mode** if your workspace allows it. 2. Open ChatGPT Plugins and select the plus button. Name the connection `OpenPost`. 3. Enter `https://app.openpo.st/mcp` as the remote MCP URL. Create the connection and review the tools it discovers. 4. Complete OpenPost sign-in when prompted. Choose a workspace and `mcp:read` for review-only work, or `mcp:full` when ChatGPT needs to create, schedule, or publish. 5. Start a new chat and add OpenPost from the tools menu. Ask, "List my OpenPost workspaces," then name one and ask, "Review this week's scheduled publications without changing anything." For a first write, ask for an unpublished draft and inspect it in OpenPost. ChatGPT may ask you to confirm write actions. Check the account, text, and time before accepting a publish or schedule action. #### If your server is private ChatGPT web cannot reach your laptop's `localhost` or a private LAN address directly. Use a public HTTPS OpenPost URL or OpenAI's Secure MCP Tunnel for a private server. The local `openpost-mcp` bridge is for desktop MCP clients, not a direct ChatGPT web connection. If the connection loses access, reopen it in ChatGPT Plugins and sign in again. If OpenPost's tool list changed, refresh the connection's metadata and start a new chat. An administrator may control access to connections and write tools in a managed workspace. See OpenAI's developer-mode connection guide for current ChatGPT controls. ### Choose an agent connection Source: [https://openpo.st/docs/mcp/choose-an-agent-connection.md](https://openpo.st/docs/mcp/choose-an-agent-connection.md) MCP, the `openpost-cli` skill, and direct CLI commands can reach the same OpenPost account, but they fit different agent environments. | | MCP | `openpost-cli` skill | Direct CLI | | ------------------- | --------------------------------------------------- | ---------------------------------------- | ------------------------------------------- | | The assistant needs | MCP support | Agent Skills and terminal access | Terminal access | | Connection | Remote HTTP or local bridge | Installed `openpost` CLI | Installed `openpost` CLI | | Guidance | Live tool schemas from OpenPost | Packaged OpenPost operating instructions | CLI help and your prompt | | Credentials | MCP OAuth or token | CLI profile or `OPENPOST_TOKEN` | CLI profile or `OPENPOST_TOKEN` | | Best use | Interactive account work in a chat or coding client | OpenPost work inside a coding-agent task | Scripts, CI, and explicit command sequences | #### Choose MCP Use MCP when the client supports it and you want OpenPost tools inside the conversation. The assistant receives current operation schemas from the server. You can grant read-only access or allow changes, and you can bind the connection to one workspace. Do not use MCP when the client cannot reach your OpenPost instance and cannot launch the local bridge. Do not add the CLI skill to solve an MCP connection problem. The skill does not configure or authenticate MCP. [Learn how OpenPost MCP works](https://openpo.st/docs/mcp/mcp-guide/index.md) #### Choose the `openpost-cli` skill Use the skill when a coding assistant supports Agent Skills and already has terminal access. The skill tells the assistant how to inspect its CLI context, choose the correct authoring command, avoid unsafe retries, and verify the result. Do not use the skill when the assistant cannot run the `openpost` command. The skill contains instructions, not an API client or credentials. It is also unnecessary when the same assistant already has a working OpenPost MCP connection. [Install and use the skill](https://openpo.st/docs/mcp/skills/index.md) #### Choose direct CLI commands Use the CLI without the skill for scripts, CI, and agents that do not support Agent Skills. Direct commands are also useful when you want an exact, repeatable command sequence and machine-readable JSON. Do not use the direct CLI when the assistant has no terminal access. For a long-lived application, use the SDK or HTTP API instead of wrapping many shell commands. [Install and use the CLI](https://openpo.st/docs/automate/cli/index.md) ### Connect Claude Code Source: [https://openpo.st/docs/mcp/claude-code.md](https://openpo.st/docs/mcp/claude-code.md) Add OpenPost as a remote server in an installed Claude Code. User scope makes it available across your projects. #### Add the server ```sh claude mcp add --transport http --scope user openpost https://app.openpo.st/mcp ``` Start Claude Code and run `/mcp`. Select `openpost` and follow the browser sign-in. Choose `mcp:read` for reviews or `mcp:full` for creating, editing, scheduling, and publishing. #### Check the connection Run `/mcp` to inspect the connection. Ask, "List my OpenPost workspaces," then name a workspace and ask Claude to review its schedule without making changes. #### Self-hosted OpenPost Replace the hosted origin with your server's HTTPS origin and keep `/mcp`. If you prefer the [local bridge](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md), install and authenticate it first, then add it instead: ```sh claude mcp add --scope user openpost -- openpost-mcp --profile local ``` Use one connection for `openpost`, not both. If authentication expires, use `/mcp` to reconnect. If the bridge is not found, configure its absolute executable path. See Claude Code MCP documentation. ### Connect Claude Desktop Source: [https://openpo.st/docs/mcp/claude-desktop.md](https://openpo.st/docs/mcp/claude-desktop.md) Claude Desktop supports a remote account connector and local tools. Choose the remote connector for Hosted; use the local bridge when your OpenPost instance is reachable only from your computer. #### Remote connector Open **Settings → Connectors** and add `https://app.openpo.st/mcp` as a custom connector named `OpenPost`. Complete browser sign-in and enable it in the conversation. The [Claude web guide](https://openpo.st/docs/mcp/claude.md) covers permissions and organization setup. Remote connectors run from Claude's cloud even when you use the desktop app. They cannot reach your computer's `localhost`. #### Local bridge First [install and sign in to the OpenPost bridge](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md). In Claude Desktop, open **Settings → Developer → Edit Config** and merge: ```json { "mcpServers": { "openpost": { "command": "openpost-mcp", "args": ["--profile", "local"] } } } ``` Use the absolute path from `command -v openpost-mcp` if the app cannot find the executable. Fully restart Claude Desktop after saving. #### Check the connection Ask, "List my OpenPost workspaces." If the local bridge fails, sign in again with the `local` profile from the same computer account that runs Claude Desktop. See the local MCP setup guide for desktop configuration details. ### Connect Claude web Source: [https://openpo.st/docs/mcp/claude.md](https://openpo.st/docs/mcp/claude.md) Use Claude's custom connector to review your schedule and prepare publications from a conversation. Your Claude account or organization must allow custom connectors. #### Add the connector 1. Open Claude's **Customize → Connectors**, or **Settings → Connectors** in interfaces that use that label. 2. Choose **Add custom connector**, name it `OpenPost`, and enter: ```text https://app.openpo.st/mcp ``` 3. Add the connector and complete OpenPost's browser sign-in. Leave optional client credentials empty; OpenPost supports dynamic registration. 4. Choose read-only access for reviews, or full access to create and publish. Enable OpenPost in the conversation's connector controls. #### Check the connection Ask, "List my OpenPost workspaces," then name one and ask for its scheduled publications. For a first write, request an unpublished draft and inspect it in OpenPost. #### If it does not connect An organization owner may need to add or allow the connector first. Claude reaches remote servers from its cloud, so self-hosted OpenPost needs a public HTTPS URL. Reconnect from the connector settings if authorization expires. Using another Claude client? See [Claude Desktop](https://openpo.st/docs/mcp/claude-desktop.md) or [Claude Code](https://openpo.st/docs/mcp/claude-code.md). See Claude custom connector setup. ### Connect Codex Source: [https://openpo.st/docs/mcp/codex.md](https://openpo.st/docs/mcp/codex.md) Connect OpenPost once to review a schedule or prepare a draft from Codex. Codex CLI, its IDE extension, and the ChatGPT desktop app share the MCP configuration for the same host. #### Add OpenPost Open **Settings → MCP servers → Add server** in the desktop app, choose **Streamable HTTP**, enter `https://app.openpo.st/mcp`, and save. Or add this entry to `~/.codex/config.toml` for Codex CLI: ```toml [mcp_servers.openpost] url = "https://app.openpo.st/mcp" ``` In the desktop app, restart and choose **Authenticate** beside OpenPost. From Codex CLI, run: ```sh codex mcp login openpost ``` Complete OpenPost's browser sign-in. Choose `mcp:read` to inspect your workspace, or `mcp:full` to let Codex change publications. Start a new session after adding the server. #### Check the connection In Codex CLI, run `codex mcp list`; in the desktop app, check the MCP server list. Then ask Codex, "List my OpenPost workspaces." Name one and ask for its schedule without making changes. #### If it does not connect Authenticate again if the login expired. Check that the configured URL ends in `/mcp`. For a private self-hosted server, use the [local bridge](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md) with `command = "openpost-mcp"` and `args = ["--profile", "local"]` in the configuration. That bridge runs on the same machine as Codex. See Codex MCP configuration for client settings. ### Connect Cursor Source: [https://openpo.st/docs/mcp/cursor.md](https://openpo.st/docs/mcp/cursor.md) Cursor supports remote Streamable HTTP MCP servers. Add OpenPost to your personal Cursor configuration, then let Cursor complete OAuth in the browser. #### Configure the server Create or edit `~/.cursor/mcp.json` for all projects, or `.cursor/mcp.json` for one project: ```json { "mcpServers": { "openpost": { "url": "https://app.openpo.st/mcp" } } } ``` Restart the Agent window, open Cursor's MCP or Customize view, and connect `openpost`. Cursor discovers OpenPost's authorization metadata and opens the sign-in page. Choose an OpenPost workspace and grant `mcp:read` for review-only work, or `mcp:full` when the agent must create, schedule, or publish. The Cursor CLI can authenticate a configured server with `agent mcp login openpost` and inspect it with `agent mcp list-tools openpost`. #### Token fallback If your version of Cursor does not offer OAuth, keep the token outside the file and use environment interpolation: ```json { "mcpServers": { "openpost": { "url": "https://app.openpo.st/mcp", "headers": { "Authorization": "Bearer ${env:OPENPOST_MCP_TOKEN}" } } } } ``` Create a developer token with the smallest OpenPost MCP scope, export `OPENPOST_MCP_TOKEN`, and restart Cursor. Do not commit a real token to a project-level config. #### Test and fix the common failures Ask Cursor, "List my OpenPost workspaces," then "Review this week's schedule without changing anything." If the server is disconnected, reload the MCP configuration and sign in again. A private self-hosted URL is not reachable by Cursor Cloud Agents; use a public HTTPS hostname or the local `openpost-mcp` stdio bridge. Use `/mcp`, not `/api/v1/mcp`. For current client controls and plan availability, see Cursor MCP documentation. ### Connect Devin Source: [https://openpo.st/docs/mcp/devin.md](https://openpo.st/docs/mcp/devin.md) Add OpenPost as a custom server in Devin's MCP marketplace. You need permission to configure integrations for your Devin organization. #### Add OpenPost 1. Open **Settings → MCP Marketplace → Add Your Own**. 2. Name the server `OpenPost` and select **HTTP** transport. 3. Enter `https://app.openpo.st/mcp`. 4. Select **OAuth**, save, and start a Devin session. Complete OpenPost's sign-in when prompted. Choose read-only access to inspect publications and accounts. Choose full access when Devin needs to prepare, schedule, or publish content. #### Check the connection Ask, "List my OpenPost workspaces," then name a workspace and request its scheduled publications. Try a draft before a publishing request: "Prepare a draft about this release. Leave it unpublished." #### If it does not connect Cloud Devin must reach your server over public HTTPS. It cannot reach `localhost` on your laptop. Check the server's HTTP transport, connection status, and authorization in the MCP settings. Devin's own MCP server exposes Devin to other clients. It is a different integration; the URL you enter here must be OpenPost's endpoint. See Devin's MCP marketplace guide. ### Connect Gemini CLI Source: [https://openpo.st/docs/mcp/gemini-cli.md](https://openpo.st/docs/mcp/gemini-cli.md) Add OpenPost to an installed Gemini CLI, then authorize the connection in your browser. #### Configure the server Merge this entry into `~/.gemini/settings.json`: ```json { "mcpServers": { "openpost": { "httpUrl": "https://app.openpo.st/mcp", "oauth": { "enabled": true } } } } ``` Use `httpUrl` for Streamable HTTP. Gemini's `url` field selects SSE, which is a different transport. #### Sign in and test Restart Gemini CLI and run: ```text /mcp auth openpost ``` Complete OpenPost's browser consent. Choose read-only access for schedule reviews, or full access to prepare and publish content. Ask, "List my OpenPost workspaces," then name your workspace and request its connected accounts. #### If it does not connect Run `/mcp auth openpost` again for an expired login. The browser callback must reach the machine running Gemini CLI. For a remote shell or private instance, consider the [local bridge](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md). See Gemini CLI MCP documentation for authentication and transport settings. ### Connect GitHub Copilot Source: [https://openpo.st/docs/mcp/github-copilot.md](https://openpo.st/docs/mcp/github-copilot.md) Copilot in VS Code uses the editor's MCP connection. Add OpenPost once, then select its tools in agent chat. #### Set up Copilot in your editor 1. Open VS Code and sign in to GitHub Copilot. 2. Follow [Connect VS Code](https://openpo.st/docs/mcp/vs-code.md) to add `https://app.openpo.st/mcp` and authorize OpenPost. 3. Open Copilot Chat in agent mode and enable the OpenPost tools. 4. Ask, "List my OpenPost workspaces," then specify the workspace you want to use. #### Try a useful task Ask, "Review this week's schedule and suggest gaps without changing any posts." With full access, try, "Prepare a draft about this release for my connected LinkedIn account. Leave it unpublished." Review the result in OpenPost before scheduling it. #### Other Copilot surfaces This setup applies to Copilot in VS Code. GitHub's hosted coding agent has its own MCP configuration and authentication rules. An editor connection does not automatically configure a GitHub-hosted agent. For missing tools, check the server status in VS Code and enable its tools for the current chat. See VS Code MCP setup for the editor controls. ### Connect Grok Source: [https://openpo.st/docs/mcp/grok.md](https://openpo.st/docs/mcp/grok.md) Grok can connect to OpenPost through a custom remote connector. Use a Grok account with access to custom connectors and an OpenPost account. #### Add the connector 1. Open Grok Connectors. 2. Choose **New Connector → Custom** and name it `OpenPost`. 3. Enter `https://app.openpo.st/mcp` as the server URL. 4. Complete the supported sign-in flow. For OAuth, sign in to OpenPost and choose read-only or full access. If configuring a bearer header instead, use an OpenPost developer token with the matching MCP scope. #### Check the connection Enable OpenPost in your conversation and ask, "List my OpenPost workspaces." Name a workspace, then request a schedule review without making changes. #### Grok Build CLI Grok Build is a separate client. Add its connection with: ```sh grok mcp add --transport http openpost https://app.openpo.st/mcp ``` Complete OAuth when prompted. A Grok web connector does not configure the CLI automatically. #### If it does not connect Grok's cloud connector needs public HTTPS. A self-hosted LAN address or `localhost` is not reachable from Grok web. Check access to custom connectors and reconnect if authorization expires. See Grok connectors and Grok Build MCP. ### Connect Hermes Agent Source: [https://openpo.st/docs/mcp/hermes.md](https://openpo.st/docs/mcp/hermes.md) Configure the Hermes installation that runs your agent. A desktop app, CLI, or messaging gateway must read the same configuration and credentials. #### Configure and sign in Merge this into `~/.hermes/config.yaml`: ```yaml mcp_servers: openpost: url: "https://app.openpo.st/mcp" auth: oauth ``` Then authenticate and test: ```sh hermes mcp login openpost hermes mcp test openpost ``` Complete the browser consent. Choose read-only access for inspection or full access for changes. Restart the agent session or use `/reload-mcp` to refresh its tools. #### Check the connection Ask, "List my OpenPost workspaces," then name one and request its scheduled publications. If Hermes does not see the tools, run the connection test again and check whether the server is enabled. #### Remote gateways Authenticate as the operating-system user running the gateway. Otherwise the agent may not find your saved credentials. On SSH or a headless host, follow Hermes' remote OAuth guide to complete the browser callback. See Hermes MCP configuration. ### AI assistants Source: [https://openpo.st/docs/mcp/index.md](https://openpo.st/docs/mcp/index.md) OpenPost supports three ways for an AI assistant to work with your account. Use one main connection for each task so the assistant has one clear instance, workspace, and permission boundary. | Connection | Best for | Start here | | -------------------- | ------------------------------------------------------------------------- | ------------------------------------- | | MCP | Chat and coding assistants with MCP support | [Connect with MCP](https://openpo.st/docs/mcp/mcp-guide/index.md) | | `openpost-cli` skill | Coding assistants that support Agent Skills and can run terminal commands | [Use the OpenPost skill](https://openpo.st/docs/mcp/skills/index.md) | | Direct CLI | Scripts, CI, and agents that can run commands but cannot load skills | [CLI guide](https://openpo.st/docs/automate/cli/index.md) | Read [Choose an agent connection](https://openpo.st/docs/mcp/choose-an-agent-connection.md) for the differences, limits, and cases where each option is the wrong fit. #### Choose a setup Use the client guides in this section to add OpenPost through MCP. Each guide covers the client-specific configuration, sign-in, and a safe first request. Start with a read request: ```text List my OpenPost workspaces. ``` Then name the workspace and ask the assistant to review its schedule without making changes. Grant write access only when the assistant needs to create or change OpenPost data. [ChatGPT](https://openpo.st/docs/mcp/chatgpt.md) [Claude web](https://openpo.st/docs/mcp/claude.md) [Claude Desktop](https://openpo.st/docs/mcp/claude-desktop.md) [Claude Code](https://openpo.st/docs/mcp/claude-code.md) [Cursor](https://openpo.st/docs/mcp/cursor.md) [Codex](https://openpo.st/docs/mcp/codex.md) [Grok](https://openpo.st/docs/mcp/grok.md) [Devin](https://openpo.st/docs/mcp/devin.md) [Perplexity](https://openpo.st/docs/mcp/perplexity.md) [Gemini CLI](https://openpo.st/docs/mcp/gemini-cli.md) [GitHub Copilot](https://openpo.st/docs/mcp/github-copilot.md) [VS Code](https://openpo.st/docs/mcp/vs-code.md) [Antigravity](https://openpo.st/docs/mcp/antigravity.md) [OpenCode](https://openpo.st/docs/mcp/opencode.md) [OpenClaw](https://openpo.st/docs/mcp/openclaw.md) [Hermes Agent](https://openpo.st/docs/mcp/hermes.md) If you are building an integration instead of asking an assistant to operate your account, use the [TypeScript SDK](https://openpo.st/docs/automate/sdk/index.md) or [HTTP API](https://openpo.st/docs/automate/api/index.md). ### Endpoints and tools Source: [https://openpo.st/docs/mcp/mcp-guide/endpoints-and-tools.md](https://openpo.st/docs/mcp/mcp-guide/endpoints-and-tools.md) OpenPost offers two MCP endpoints. They use the same authentication, scopes, workspace checks, validation, and operation behavior. #### Direct tools Use the default endpoint for most clients: ```text https://app.openpo.st/mcp ``` It lists each available operation as a separate tool. An assistant can call tools such as `list_workspaces`, `list_publications`, or `create_publication` with the operation's own input schema. Choose this endpoint when the client handles a full tool catalog well. It gives the assistant the clearest tool names and schemas at the start of the session. #### Compact tools Use the compact endpoint when the client has a strict tool or context limit: ```text https://app.openpo.st/mcp/code ``` It exposes a small routing set: - `search_operations` finds matching OpenPost operations and returns their schemas and safety information. - `query_operation` runs only read-only operations. - `execute_operation` runs only operations that change state or interact with an external service. A read-only connection does not receive `execute_operation`. Search results also exclude write operations. The server rejects an operation passed through the wrong execution tool. The compact endpoint does not run model-written code. It reduces the initial tool list and still sends each request through OpenPost's typed operation handlers. #### Self-hosted tool mode Self-hosted operators can set `OPENPOST_MCP_MODE` to control the catalog at `/mcp`: | Value | `/mcp` tool list | | -------- | ------------------------------------------------------------------- | | `direct` | Individual operation tools. This is the default. | | `search` | Compact search, read, and write tools, plus compatible app widgets. | | `both` | Individual operation tools and the compact tools. | `/mcp/code` always uses the compact list. Changing the tool list does not change permissions. Some clients cache tool definitions. Refresh the MCP server metadata or start a new session after changing endpoints or modes. ### Connect with MCP Source: [https://openpo.st/docs/mcp/mcp-guide/index.md](https://openpo.st/docs/mcp/mcp-guide/index.md) MCP gives an AI assistant live OpenPost tools. The assistant can inspect accounts, media, Publications, Renditions, schedules, and delivery results. With write access, it can also prepare drafts, change Publications, schedule work, publish, and manage supported comments. Use MCP when your assistant supports a remote HTTP server or a local MCP command. You do not need the `openpost-cli` skill for an MCP connection. #### Hosted endpoint Most clients should connect to: ```text https://app.openpo.st/mcp ``` The client opens OpenPost sign-in through OAuth when it supports browser authentication. Choose `mcp:read` for review work. Choose `mcp:full` only when the assistant needs to create or change data. If the client cannot use OAuth, create a developer token in **Settings → Personal → Developer** and add it as a bearer token in the client's secure authentication settings. Do not paste the token into a conversation or commit it to a configuration file. #### First connection check After connecting, ask: ```text List my OpenPost workspaces. ``` Choose one of the returned workspaces, then ask: ```text Review this week's scheduled Publications without changing anything. ``` This confirms the account, workspace, and read permissions before any write request. #### Continue - [Choose the full or compact endpoint](https://openpo.st/docs/mcp/mcp-guide/endpoints-and-tools.md) - [Set permissions and approval rules](https://openpo.st/docs/mcp/mcp-guide/permissions-and-safety.md) - [Use local files or media URLs](https://openpo.st/docs/mcp/mcp-guide/media.md) - [Connect a self-hosted instance](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md) - [Try practical read and write tasks](https://openpo.st/docs/mcp/mcp-guide/use-cases.md) ### Media and local files Source: [https://openpo.st/docs/mcp/mcp-guide/media.md](https://openpo.st/docs/mcp/mcp-guide/media.md) An MCP assistant can reuse media that is already in the selected OpenPost workspace. Ask it to list recent media, choose the correct item, and attach the returned media ID to a Publication. #### Upload from a public URL With `mcp:full`, an assistant can use `upload_media_from_url` for a public HTTP or HTTPS URL. OpenPost rejects URLs that resolve to private, loopback, link-local, multicast, or other local network addresses. OpenPost downloads the file and applies the normal media limits, workspace permissions, quota, storage, deduplication, and analysis checks. A URL upload creates a workspace media item that the assistant can attach to a Publication. Use this path only when the media is already available at a public URL. Do not create a temporary public link for a private file when your client supports local uploads. #### Upload a local file A compatible MCP Apps client can open OpenPost's file picker through `render_local_media_upload`. This requires `mcp:full`. The file travels from the app to OpenPost. Its bytes and upload credential do not enter the model's conversation context. The one-use upload ticket expires after ten minutes and is bound to the authenticated actor and selected workspace. The local picker works only in clients that support MCP Apps UI and app-only tool calls. If the client does not support it, upload the file in OpenPost first and ask the assistant to use the resulting media item. #### Check the result After an upload, ask the assistant to confirm the media item's ID, type, dimensions or duration, and analysis state. Add alt text before publishing an image when the destination supports it. ### Permissions and safety Source: [https://openpo.st/docs/mcp/mcp-guide/permissions-and-safety.md](https://openpo.st/docs/mcp/mcp-guide/permissions-and-safety.md) OpenPost checks the token scope and workspace access for every MCP operation. The client may add its own approval prompt, but client approval does not replace OpenPost permissions. #### Choose a scope | Scope | Access | | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `mcp:read` | Inspect workspaces, accounts, media, Publications, schedules, readiness, comments, and lifecycle events. It cannot change OpenPost data. | | `mcp:full` | Includes read access and permits operations that create, edit, schedule, publish, upload, reply, or moderate. | OpenPost defaults an OAuth request with no scope to `mcp:full`. Select `mcp:read` explicitly for reviews and audits. Bind the connection or developer token to one workspace when the assistant does not need access to every workspace. A workspace-bound token cannot list or target another workspace. #### Separate review from action Start with `mcp:read` when the task is to inspect a schedule, check readiness, find delivery failures, or suggest changes. Move to `mcp:full` only for the step that needs a write. For write tasks, tell the assistant where to stop: ```text Create an unpublished draft for my review. Do not schedule or publish it. ``` Before publishing, check the workspace, destination accounts, text, media, and time. A scheduled or queued Publication is not published. Ask the assistant to inspect the Publication's Renditions and lifecycle events when delivery is partial or fails. #### Protect credentials Use browser OAuth when the client supports it. Otherwise, store a developer token in the client's secure settings or environment. Never put an OpenPost token, provider credential, or server secret in a prompt. Recent MCP calls appear under **Settings → Personal → Developer access**. Use that activity to identify the client, tool, workspace, result, and failure reason. ### Self-hosted and local connections Source: [https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md](https://openpo.st/docs/mcp/mcp-guide/self-hosted-and-local.md) Use remote HTTP when the client can reach your OpenPost instance. Use the local bridge when a desktop client can reach the instance from your computer but the client's cloud service cannot. #### Public HTTPS instance Replace the Hosted origin with your own origin and keep the MCP path: ```text https://openpost.example.com/mcp ``` Use `/mcp/code` instead when you need the compact tool list. Your reverse proxy must serve the instance over HTTPS, preserve authorization headers, and forward POST requests to OpenPost. OAuth-aware clients also use the discovery paths under `/.well-known/`. #### Private instance with a desktop client Install the CLI and `openpost-mcp` bridge: ```sh curl -fsSL https://raw.githubusercontent.com/getopenpost/openpost/main/scripts/install-cli.sh | sh -s -- --with-mcp ``` Sign in to the instance with a named CLI profile: ```sh openpost --profile local auth login https://openpost.internal.example ``` Configure the MCP client to launch the bridge with the same profile: ```json { "mcpServers": { "openpost": { "command": "openpost-mcp", "args": ["--profile", "local"] } } } ``` The bridge reads the saved CLI profile and token, then forwards MCP messages to the instance's `/mcp` endpoint. The client starts the process, so you do not need to keep a separate terminal open. If the client cannot find the command, replace `openpost-mcp` with the path returned by: ```sh command -v openpost-mcp ``` #### Cloud clients A cloud client cannot use `localhost` or a private LAN address on your computer. Give it a public HTTPS instance if the product supports remote custom MCP servers. A local bridge works only when the MCP process runs on a machine that can reach OpenPost. Use the setup page for your client to confirm its transport and configuration format. Do not configure the remote endpoint and the local bridge under the same server name. ### MCP use cases Source: [https://openpo.st/docs/mcp/mcp-guide/use-cases.md](https://openpo.st/docs/mcp/mcp-guide/use-cases.md) Name the OpenPost workspace in every task after the first connection check. Tell the assistant whether it may change data and where it must stop for review. #### Review a schedule Use `mcp:read`: ```text Review next week's scheduled Publications in the Personal workspace. Group them by destination, flag empty days and missing media, and do not change anything. ``` The assistant can inspect Publications, Renditions, connected accounts, media, and posting slots without gaining write access. #### Check provider readiness Use `mcp:read` before planning work for a new destination: ```text Check whether the Company workspace and its LinkedIn account are ready to publish an image post. Report each blocker without changing settings. ``` This prevents the assistant from drafting against an unavailable provider, disconnected account, or unsupported format. #### Prepare a draft Use `mcp:full`, but stop before scheduling: ```text Create an unpublished launch draft for the Company workspace and its connected LinkedIn account. Reuse the newest matching image in the media library. Stop after creating the draft. ``` Inspect the saved Publication in OpenPost. Check each destination Rendition before asking the assistant to schedule it. #### Schedule approved work Use `mcp:full` and provide an exact time or ask for an available posting slot: ```text Validate Publication pub_123. If it passes, schedule it in the next available Company workspace slot. Report the saved time and job state. ``` Treat `scheduled` and `queued` as intermediate states. They do not prove that a provider published the content. #### Investigate a failed destination Use `mcp:read` first: ```text Inspect Publication pub_123, its Renditions, and lifecycle events. Explain which destinations succeeded or failed and quote the saved failure reason. Do not retry anything. ``` Grant `mcp:full` only if you then want the assistant to make a correction or retry an authorized destination. ### Connect OpenClaw Source: [https://openpo.st/docs/mcp/openclaw.md](https://openpo.st/docs/mcp/openclaw.md) Register OpenPost on the machine running OpenClaw. The current CLI uses `mcp set` to save a server definition. #### Add and authorize ```sh openclaw mcp set openpost \ '{"url":"https://app.openpo.st/mcp","transport":"streamable-http","auth":"oauth"}' openclaw mcp login openpost ``` Complete the sign-in instructions printed by OpenClaw. Choose read-only access to inspect publications, or full access to let the agent change them. #### Check the connection ```sh openclaw mcp doctor --probe ``` Restart your active agent or gateway to refresh its tool list. Ask, "List my OpenPost workspaces," then name one and ask for this week's schedule without changing anything. #### If it does not connect If `mcp set` is unavailable, check your installed OpenClaw version against the current CLI guide. Run `openclaw mcp login openpost` again for an expired authorization. For a remote gateway, finish login on the host that stores the gateway's configuration. A self-hosted URL must be reachable from the OpenClaw host. A gateway running elsewhere cannot use `localhost` to reach your laptop. See OpenClaw MCP commands. ### Connect OpenCode Source: [https://openpo.st/docs/mcp/opencode.md](https://openpo.st/docs/mcp/opencode.md) Add OpenPost as a remote server in OpenCode. OpenCode can open the browser sign-in when it first reaches a server that requires OAuth. #### Configure the server Merge this entry into your OpenCode configuration, such as `opencode.json`: ```json { "mcp": { "openpost": { "type": "remote", "url": "https://app.openpo.st/mcp" } } } ``` The server name belongs directly under `mcp`. OpenCode's current MCP configuration guide uses this shape for remote servers. #### Authorize and test ```sh opencode mcp auth openpost opencode mcp list ``` Complete OpenPost's consent with read-only access for reviews or full access for changes. Start a session and ask, "List my OpenPost workspaces," then request the schedule for a named workspace. #### If it does not connect Use `opencode mcp debug openpost` to investigate authentication. Re-run `opencode mcp auth openpost` if your login expired. Check that the URL ends in `/mcp` and is reachable from the machine running OpenCode. See OpenCode MCP configuration for the current schema. ### Connect Perplexity Source: [https://openpo.st/docs/mcp/perplexity.md](https://openpo.st/docs/mcp/perplexity.md) Use a Perplexity account with custom remote connectors enabled. An organization administrator may control which connectors you can add. #### Add the remote connector 1. Open **Account Settings → Connectors**. 2. Add a **Custom connector** and choose **Remote**. 3. Name it `OpenPost` and enter `https://app.openpo.st/mcp`. 4. Select OAuth and complete the OpenPost sign-in. Choose read-only access for reviews or full access for changes. If your connector configuration uses a bearer header instead, create an OpenPost developer token with `mcp:read` or `mcp:full` and enter it in the connector's authentication settings, not in a conversation. #### Check the connection Enable the connector for your conversation or Computer workflow. Ask, "List my OpenPost workspaces," then request the schedule for a named workspace without changing anything. #### If it does not connect Check that your account exposes custom remote connectors and that the connector is enabled for this conversation. Reconnect after an expired authorization. Self-hosted OpenPost must have a publicly reachable HTTPS URL; Perplexity's cloud cannot reach your laptop's `localhost`. See Perplexity's remote connector announcement. ### OpenPost skills Source: [https://openpo.st/docs/mcp/skills/index.md](https://openpo.st/docs/mcp/skills/index.md) An Agent Skill is a set of instructions and supporting reference files that a compatible assistant can load for a task. It does not add a network connection, install a CLI, or store credentials. OpenPost currently publishes one public skill: `openpost-cli`. It teaches an assistant how to operate a running OpenPost instance through the `openpost` command. The skill covers: - checking the current instance, identity, and workspace before an action; - choosing between text posts, threads, and format-first Publications; - checking provider readiness and capabilities; - treating schedule, publish, retry, moderation, and deletion commands as changes; - verifying saved objects, jobs, Renditions, and lifecycle events after a change. Use the skill when a coding assistant supports Agent Skills and can run terminal commands. Use [MCP](https://openpo.st/docs/mcp/mcp-guide/index.md) instead when the assistant already has a working MCP connection. Use the [CLI directly](https://openpo.st/docs/automate/cli/index.md) for scripts, CI, or assistants that cannot load skills. #### Continue - [Install the skill and CLI](https://openpo.st/docs/mcp/skills/install.md) - [Understand how the CLI skill works](https://openpo.st/docs/mcp/skills/openpost-cli.md) - [Try practical skill use cases](https://openpo.st/docs/mcp/skills/use-cases.md) ### Install the OpenPost skill Source: [https://openpo.st/docs/mcp/skills/install.md](https://openpo.st/docs/mcp/skills/install.md) The `openpost-cli` skill needs the `openpost` command. Install and authenticate the CLI before asking an assistant to use the skill. #### Install the CLI Install the npm wrapper: ```sh npm install -g @getopenpost/cli ``` Sign in and confirm the CLI context: ```sh openpost auth login https://app.openpo.st openpost auth status --json openpost workspace list --json ``` For a self-hosted instance, replace the Hosted origin with your instance URL. #### Install the skill Use the Agent Skills installer for a compatible assistant: ```sh npx skills add https://github.com/getopenpost/openpost --skill openpost-cli ``` The skill is also published as a deterministic archive at openpo.st/.well-known/agent-skills/openpost-cli.tar.gz for clients that support Agent Skills discovery or archive installation. Installation controls differ by assistant. Follow the assistant's Agent Skills documentation when it does not support the `npx skills` command. #### Check the setup Start a new assistant session so it can discover the skill. Ask it to use `openpost-cli` to inspect the current OpenPost context without making changes. The assistant should run commands such as: ```sh openpost instance diagnostics --json openpost auth status --json openpost workspace list --json ``` If the `openpost` command is missing, install the CLI. If authentication is missing, sign in yourself. The skill should not install software or create credentials unless you explicitly ask for that action. ### How the CLI skill works Source: [https://openpo.st/docs/mcp/skills/openpost-cli.md](https://openpo.st/docs/mcp/skills/openpost-cli.md) The `openpost-cli` skill gives an assistant OpenPost-specific operating rules. The assistant still runs the installed `openpost` CLI, which uses a saved profile or `OPENPOST_TOKEN` to reach your instance. #### Before an action The skill tells the assistant to inspect the active instance, identity, and available workspaces. It uses `--json` for reads so it can parse IDs and status fields instead of scraping terminal tables. When the saved context is missing or ambiguous, the assistant should pass an explicit `--profile`, `--instance`, or `--workspace` value. It should use the stored keyring token or environment token without printing it. #### Choosing the authoring command The skill distinguishes the main CLI paths: - `openpost post` handles short text, text with media, and editable text drafts. - `openpost thread create` reads two or more posts separated by `---` from a Markdown file. - `openpost publication` handles format-first work such as link shares, image posts, carousels, stories, short video, long video, and provider-specific settings. It also directs the assistant to check provider readiness and capabilities before using a new destination or format. #### Changes and approval The skill treats scheduling, publishing, retries, comment moderation, account disconnection, slot generation, and deletion as changes. The assistant should run them only when your request authorizes that effect. It should default to an unpublished draft when you did not ask to schedule or publish. It should not add `--force` after a revision conflict or bypass an interactive confirmation without your authorization. #### Result checks After a change, the assistant should read the saved object and current server state. For Publication work, that includes the Publication, lifecycle events, related job, and each destination Rendition. The skill does not make the assistant infallible. Read the proposed command before a destructive or public action, and inspect the result in OpenPost. ### CLI skill use cases Source: [https://openpo.st/docs/mcp/skills/use-cases.md](https://openpo.st/docs/mcp/skills/use-cases.md) Tell the assistant which OpenPost instance and workspace to use. State whether it may change data. The skill helps it choose commands and verify results, but your request still defines the authorized action. #### Inspect an account without changes ```text Use the openpost-cli skill. Inspect my current OpenPost profile, list my workspaces, and show the connected accounts in the Personal workspace. Use JSON output and make no changes. ``` #### Prepare a format-first draft ```text Use the openpost-cli skill to create an unpublished LinkedIn link-share Publication in the Company workspace. Check provider readiness and capabilities first. Validate the saved Publication and stop before scheduling. ``` The assistant should choose `openpost publication`, resolve an exact account, create the draft, then run validation and read back the result. #### Create a thread from a file ```text Use the openpost-cli skill to create a draft thread from ./launch-thread.md for the Company X account. Do not schedule or publish it. ``` The skill tells the assistant to use `openpost thread create` when the Markdown file contains two or more `---`-separated posts. #### Schedule approved work ```text Use the openpost-cli skill to validate Publication pub_123 and schedule it for 2026-10-02T14:00:00+01:00. Confirm the exact workspace and accounts before the write. Report the saved time and job state. ``` #### Investigate a failure ```text Use the openpost-cli skill to inspect Publication pub_123, its Renditions, lifecycle events, and recent jobs. Explain the failure and do not retry it. ``` If you later authorize a retry, name the exact failed Rendition. The assistant should verify the new lifecycle state after the command. ### Connect VS Code Source: [https://openpo.st/docs/mcp/vs-code.md](https://openpo.st/docs/mcp/vs-code.md) Use an installed VS Code with Copilot agent chat available. The editor manages the MCP connection and browser sign-in. #### Add the server Open the Command Palette and run **MCP: Add Server**. Choose **HTTP**, enter `https://app.openpo.st/mcp`, and name the server `openpost`. Choose user configuration to use it across projects, or workspace configuration for this project. A workspace `.vscode/mcp.json` looks like this: ```json { "servers": { "openpost": { "type": "http", "url": "https://app.openpo.st/mcp" } } } ``` The top-level key is `servers`, not `mcpServers`. #### Authorize and test Start the server from its configuration and complete the OpenPost sign-in. Select read-only access for a first connection. In agent chat, enable the OpenPost tools and ask, "List my OpenPost workspaces." #### If tools are missing Use **MCP: List Servers** to inspect the server status and output. Check that the current chat has the tools enabled. A new login can resolve an expired authorization. See VS Code MCP setup. ## Self-hosting ### AI providers Source: [https://openpo.st/docs/self-hosting/ai.md](https://openpo.st/docs/self-hosting/ai.md) OpenPost's server-side AI features use OpenRouter. They are optional. Without an OpenRouter key, people can still write, edit, schedule, and publish posts; the AI builder and automatic image captions are unavailable. #### Add a key 1. Create an API key in OpenRouter. Check the account's billing and model access before inviting others to use generation. 2. Add the key to the `.env` file used by your OpenPost container. Choose model IDs available to that key: ```dotenv OPENROUTER_API_KEY=your-openrouter-key OPENPOST_TEXT_GENERATION_MODEL=openai/gpt-5.6-luna OPENPOST_IMAGE_CAPTION_MODEL=openai/gpt-5.6-luna ``` Run `docker compose up -d --force-recreate openpost` to recreate the container with the new environment. The text model builds publication copy from an idea. The image caption model writes suggested alt text. The shown IDs match this release's defaults; confirm that OpenRouter still offers them before relying on the example. You can leave the model values unset to use OpenPost's defaults. `OPENPOST_CONTENT_AI_PROVIDER` optionally selects an exact OpenRouter provider for text and meme generation. `OPENPOST_CONTENT_AI_REQUIRE_ZDR=true` restricts those requests to zero-retention endpoints. Use it only after checking that the selected model and provider support that policy. OpenRouter documents its per-request zero-retention behavior. Image captions have separate `OPENPOST_IMAGE_CAPTION_PROVIDER` and `OPENPOST_IMAGE_CAPTION_REQUIRE_ZDR` settings when you need different routing. Keep the key on the server. You can use `OPENROUTER_API_KEY_FILE` for a mounted secret file instead of putting the value in `.env`. Do not put it in a publication, prompt, log, or browser code. #### Check the setup 1. Open a new publication and ask the AI builder to turn a short idea into a draft. Review the generated copy before saving or publishing. 2. Add an image with no existing alt text to the composer and generate a caption. Review it before publishing. Existing alt text is kept. Post generation sends the idea and selected context to the configured model through OpenRouter. Automatic alt text sends a 400 px JPEG thumbnail and up to 1,000 characters of relevant post text, rather than the original image. Background removal, video editing, and local transcription run in the browser and do not require this key. If a request fails, check the container logs for an OpenRouter error, then check the key, model ID, balance, provider slug, and zero-retention setting. A text-only model may not be suitable for image captions. ### Install from a binary Source: [https://openpo.st/docs/self-hosting/binary.md](https://openpo.st/docs/self-hosting/binary.md) OpenPost release binaries include the web app, API, and worker. Use one when you want to run OpenPost without a container runtime. Releases support Linux x86_64, macOS Apple Silicon, and Windows x86_64. #### Before you start - Choose stable, private paths for the database, media, and `.env` file. - Put OpenPost behind HTTPS before connecting social accounts. - Run the binary as a service so it starts again after a reboot. #### Install 1. Download the asset for your platform from GitHub Releases. 2. Create a private `.env` with the binary environment template. Set stable database and media paths, the three public URLs, and two independent secrets. 3. Make the binary executable on Linux or macOS, then start it from the directory that contains `.env`. With no role argument, OpenPost runs migrations, serves HTTP, and processes background jobs. 4. Install the systemd unit on Linux, or configure a Windows service wrapper. Keep its working directory beside `.env`. 5. Put a [reverse proxy](https://openpo.st/docs/self-hosting/reverse-proxy.md) in front of port `8080`, open the app, and create the first account. It becomes the instance administrator. Larger deployments can run `migrate` once, then start separate `web` and `worker` processes from the same release and configuration. The binary reference covers these roles. #### Updates and backups Back up the database, media directory, and `.env` together. Stop the service, replace the binary, restore its ownership and permissions, then start the service and check `/api/v1/ready`. A rollback may also require the backup made for the previous version because database migrations are not always backward compatible. #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Back up your instance](https://openpo.st/docs/self-hosting/maintenance.md) before relying on it for scheduled posts. ### Install on CasaOS Source: [https://openpo.st/docs/self-hosting/casaos.md](https://openpo.st/docs/self-hosting/casaos.md) Import OpenPost as a CasaOS customized app with the supplied Compose file. The image supports x86_64 devices. Other architectures need amd64 emulation. #### What you need - A CasaOS device with the App Store available. - Its local IP address. The Compose file uses `10.0.0.1` as an example. - A public HTTPS address before you connect social accounts. Generate two secrets and keep them private: ```sh openssl rand -base64 32 openssl rand -base64 32 ``` #### Import the app 1. Download `deploy/casaos/docker-compose.yml`. 2. Replace `10.0.0.1` with your CasaOS device's IP address in `OPENPOST_APP_URL`, `OPENPOST_PUBLIC_URL`, and `OPENPOST_MEDIA_URL`. 3. Replace the two `REPLACE-WITH-GENERATED-...` values with the secrets you generated. 4. In CasaOS, open the App Store, choose **"+" → Install a customized app → Import**, and paste the edited file. 5. Check the image, port `8080`, and `openpost_data` volume, then install the app. 6. Open `http://:8080` and create the first account. It becomes the instance administrator. CasaOS stores the environment values in the imported definition instead of a separate `.env` file. Protect your edited copy because it contains both secrets. #### Before connecting providers Replace the three local URLs with your [public HTTPS addresses](https://openpo.st/docs/self-hosting/reverse-proxy.md), then import the updated definition. Keep the `openpost_data` volume. Confirm readiness through the public address before connecting providers: ```sh curl https://post.example.com/api/v1/ready ``` #### Update and back up Use a versioned image tag from GitHub Releases. Before changing it, stop OpenPost and back up the `openpost_data` volume with the edited Compose file. Import the updated definition, then check `/api/v1/ready`. Keep backups private and off the device. A rollback may require the backup made for the previous version because database migrations are not always backward compatible. See [Maintenance](https://openpo.st/docs/self-hosting/maintenance.md) for the restore checklist. #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Back up your instance](https://openpo.st/docs/self-hosting/maintenance.md) before relying on it for scheduled posts. ### Configuration Source: [https://openpo.st/docs/self-hosting/configuration.md](https://openpo.st/docs/self-hosting/configuration.md) The Docker Compose example reads `.env` when the container starts. Keep deployment settings there or in your secret store. OpenPost also has **Settings → Instance → Configuration** for settings it can store encrypted in its database. Environment values, including `_FILE` secrets, take precedence over matching database settings. Recreate the container with `docker compose up -d --force-recreate openpost` after changing `.env`. A plain restart keeps the previous environment. #### Public addresses | Setting | What to enter | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `OPENPOST_APP_URL` | The public origin users open, such as `https://post.example.com`. OAuth callbacks derive from this value. | | `OPENPOST_PUBLIC_URL` | The public origin used for server links and Telegram's webhook. Usually the same as the app URL. | | `OPENPOST_MEDIA_URL` | A public URL for media, such as `https://post.example.com/media`, or the default `/media` path when the public origin serves media. | Use HTTPS for a public instance and make sure your proxy forwards API and media requests. Set these URLs before registering provider callbacks. Changing the app URL later can require updating callback URLs in provider portals and reconnecting accounts. [Provider integrations](https://openpo.st/docs/self-hosting/integrations/index.md) lists the callback for each provider. #### Storage The [Compose setup](https://openpo.st/docs/self-hosting/index.md) stores SQLite at `/data/db/openpost.db` and media at `/data/media`. Both paths sit under the persistent `./data` bind mount. Do not put only the database on persistent storage; published media and draft attachments live in the media directory. For PostgreSQL, set `OPENPOST_DATABASE_DRIVER=postgres` and `OPENPOST_DATABASE_URL` to the connection string. For S3-compatible storage, set `OPENPOST_STORAGE_DRIVER=s3`, `OPENPOST_S3_ENDPOINT`, `OPENPOST_S3_REGION`, `OPENPOST_S3_BUCKET`, `OPENPOST_S3_ACCESS_KEY_ID`, `OPENPOST_S3_SECRET_ACCESS_KEY`, and `OPENPOST_S3_PUBLIC_BASE_URL`. Set `OPENPOST_S3_FORCE_PATH_STYLE=true` only if your object store needs it. These are deployment choices; moving an existing instance's data needs a planned migration, not just a setting change. The MCP endpoint lists every operation directly by default. Set `OPENPOST_MCP_MODE=search` to make `/mcp` use the compact search, query, and execute surface, or `OPENPOST_MCP_MODE=both` to advertise both surfaces. The separate `/mcp/code` endpoint is always compact and needs no environment change. See [MCP endpoints and tools](https://openpo.st/docs/mcp/mcp-guide/endpoints-and-tools.md) before changing the default. Back up the database, media, Compose file, and secrets as one [restore set](https://openpo.st/docs/self-hosting/maintenance.md). #### Provider apps For OAuth platforms, create an app in the provider's portal, register the exact callback, and save supported credentials in [Instance → Configuration → Provider apps](https://openpo.st/docs/self-hosting/integrations/index.md#save-your-provider-credentials) or `OPENPOST_PROVIDER_APPS`. Telegram bot credentials use `OPENPOST_PROVIDER_APPS`; the current Instance form does not accept them. Environment-defined apps are read-only in Settings and take precedence over database entries. Recreate the container after changing environment configuration. | Provider | Setup requirement | | ---------------------------- | ----------------------------------------------------------------------------------- | | X | OAuth callback registered in the X developer app | | LinkedIn | LinkedIn app with the required products and permissions | | Threads, Facebook, Instagram | Meta app with the required product, account type, and permissions | | TikTok | App configured for the chosen posting product, review may be required | | YouTube | Google OAuth client with YouTube API enabled | | Mastodon | Automatic registration on a public server or a fixed app per server | | Bluesky | No provider app; each user creates an app password | | Discord | Incoming webhook URL for a fixed channel | | Telegram | Instance bot credentials, public HTTPS webhook, and administrator readiness records | | Pinterest | Developer app, Standard access, and administrator readiness records | Provider rules and app review can change. Start with one account and test one post before adding more providers. Telegram, Pinterest, and Discord bot mode need the additional [administrator readiness workflow](https://openpo.st/docs/self-hosting/integrations/index.md#readiness-records-for-bot-apps-and-pinterest) before normal use. Discord webhooks do not need it. #### Useful controls Set `OPENPOST_DISABLE_REGISTRATIONS=true` after creating the first administrator if only invited people should join. Set up mail before enabling `OPENPOST_EMAIL_VERIFICATION_REQUIRED=true`. Keep `OPENPOST_JWT_SECRET` and `OPENPOST_ENCRYPTION_KEY` private and stable: changing the encryption key without its previous key material can make saved provider credentials unreadable. Use `OPENPOST_EXTRA_CORS_ORIGINS` only for other origins that need browser API access; normal same-origin use needs no entry. ### Install on Coolify Source: [https://openpo.st/docs/self-hosting/coolify.md](https://openpo.st/docs/self-hosting/coolify.md) Deploy OpenPost from Git with Coolify's Docker Compose build pack and the supplied `deploy/coolify/docker-compose.yml`. The image supports x86_64 servers. Other architectures need amd64 emulation. #### What you need - A Coolify project and environment. - A domain pointed at the server (for example `post.example.com`). - Two independent secrets generated with `openssl rand -base64 32`. Add these values under **Configuration → Environment Variables** with Runtime scope: | Variable | What to enter | | -------------------------------- | -------------------------------------------------------------------------- | | `OPENPOST_APP_URL` | `https://post.example.com` | | `OPENPOST_PUBLIC_URL` | `https://post.example.com` | | `OPENPOST_MEDIA_URL` | `https://post.example.com/media` | | `OPENPOST_JWT_SECRET` | Fresh output of `openssl rand -base64 32` | | `OPENPOST_ENCRYPTION_KEY` | A second, independent `openssl rand -base64 32` value | | `OPENPOST_DISABLE_REGISTRATIONS` | `true` once the first administrator exists (optional, defaults to `false`) | Keep both secrets stable across restarts and restores. Do not commit them to the repository. #### Deploy 1. Create a **Public Repository** resource with `https://github.com/getopenpost/openpost`. Use a deploy key or GitHub App for a private fork. 2. Set the build pack to **Docker Compose**, with **Base Directory** `/` and **Docker Compose Location** `deploy/coolify/docker-compose.yml`. 3. Enter the environment variables above. 4. Set the `openpost` service domain to `https://post.example.com:8080`. The port suffix tells Coolify where to route traffic; visitors still use normal HTTPS. 5. Deploy, then verify: ```sh curl https://post.example.com/api/v1/ready ``` Expect `"status":"ready"` and `"database":"ok"`. If it fails, inspect the deployment logs and confirm that all three URL variables use the same public origin. Open the app and create the first account. It becomes the instance administrator. The deployment stores SQLite and media in the `openpost_data` volume. #### Updates and backups Pin `image:` to a release tag, then redeploy that commit to upgrade. Before changing it, back up the `openpost_data` volume and environment values, and record the current image tag. Coolify stores the volume on its host, not inside the container. Keep backups private and off the server. A rollback may require the backup made for the previous version. Follow the [maintenance checklist](https://openpo.st/docs/self-hosting/maintenance.md). #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Set up email](https://openpo.st/docs/self-hosting/email.md) before requiring email verification. ### Try it with Docker run Source: [https://openpo.st/docs/self-hosting/docker-run.md](https://openpo.st/docs/self-hosting/docker-run.md) Use `docker run` for a local trial. Use [Docker Compose](https://openpo.st/docs/self-hosting/index.md) for a lasting installation so its configuration can be reviewed, backed up, and updated as one file. #### Try it Create `.env` with the URLs and secrets from the [Compose setup](https://openpo.st/docs/self-hosting/index.md#install-with-docker-compose), then run the published `linux/amd64` image: ```sh docker volume create openpost_data docker run -d --platform linux/amd64 --name openpost --restart unless-stopped \ -p 8080:8080 --mount source=openpost_data,target=/data --env-file .env \ -e OPENPOST_DATABASE_PATH=/data/db/openpost.db \ -e OPENPOST_MEDIA_PATH=/data/media \ -e OPENPOST_MEDIA_URL=http://localhost:8080/media \ ghcr.io/getopenpost/openpost:latest ``` Open `http://localhost:8080`, create the first account, and check `http://localhost:8080/api/v1/ready` for `"status":"ready"` and `"database":"ok"`. #### Make it permanent Move to [Docker Compose](https://openpo.st/docs/self-hosting/index.md) before connecting social accounts. Keep the same secrets, attach the existing `openpost_data` volume if you need the trial data, and replace the local URLs with the final HTTPS origin. Then configure [provider integrations](https://openpo.st/docs/self-hosting/integrations/index.md) and [backups](https://openpo.st/docs/self-hosting/maintenance.md). ### Install on Dockge Source: [https://openpo.st/docs/self-hosting/dockge.md](https://openpo.st/docs/self-hosting/dockge.md) Create a Dockge stack with the supplied `deploy/dockge/compose.yaml`. Dockge keeps the Compose file and `.env` on the host, so the same stack also works with the Docker Compose CLI. The image supports x86_64 hosts. Other architectures need amd64 emulation. #### What you need - Dockge connected to a Docker host. Its default stacks directory is `/opt/stacks`. - A public HTTPS address before you connect social accounts. #### Create the stack 1. In Dockge, choose **Create Stack** and name it `openpost` (lowercase letters, numbers, underscores, and hyphens only). 2. Paste `deploy/dockge/compose.yaml` into the stack editor. 3. Add a `.env` file to the stack with one line per `${...}` value: ```dotenv OPENPOST_APP_URL=https://post.example.com OPENPOST_PUBLIC_URL=https://post.example.com OPENPOST_MEDIA_URL=https://post.example.com/media OPENPOST_JWT_SECRET=paste-openssl-rand-base64-32-output-here OPENPOST_ENCRYPTION_KEY=paste-a-second-independent-value-here OPENPOST_DISABLE_REGISTRATIONS=false ``` Generate each secret with `openssl rand -base64 32`. Keep both stable across restarts and restores. 4. Deploy the stack. Dockge stores its files under `/opt/stacks/openpost/` by default. Keep OpenPost secrets in the stack `.env`, not a shared `global.env`. 5. Verify readiness: ```sh curl https://post.example.com/api/v1/ready ``` Expect `"status":"ready"` and `"database":"ok"`. If it fails, inspect the stack logs and confirm that all three URL variables use the same public origin. Open the app and create the first account. It becomes the instance administrator. The stack stores SQLite and media in the `openpost_data` volume. #### Updates and backups Pin `image:` to a release tag. To upgrade, change the tag and redeploy, then check `/api/v1/ready`. Back up `openpost_data`, `compose.yaml`, and `.env` first, and record the current image tag. Keep backups private and off the server. A rollback may require the backup made for the previous version. Follow the [maintenance checklist](https://openpo.st/docs/self-hosting/maintenance.md). #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Back up your instance](https://openpo.st/docs/self-hosting/maintenance.md) before relying on it for scheduled posts. ### Install on Dokploy Source: [https://openpo.st/docs/self-hosting/dokploy.md](https://openpo.st/docs/self-hosting/dokploy.md) Deploy OpenPost as a Dokploy Compose service with the supplied `deploy/dokploy/docker-compose.yml`. The image supports x86_64 servers. Other architectures need amd64 emulation. #### Deploy 1. In Dokploy, create a **Compose** service. 2. Paste `deploy/dokploy/docker-compose.yml` into the Compose definition. 3. Add a domain pointing at the service's port `8080`, then set these environment variables: | Variable | What to enter | | -------------------------------- | --------------------------------------------------------- | | `OPENPOST_APP_URL` | `https://post.example.com` | | `OPENPOST_PUBLIC_URL` | `https://post.example.com` | | `OPENPOST_MEDIA_URL` | `https://post.example.com/media` | | `OPENPOST_JWT_SECRET` | Fresh output of `openssl rand -base64 32` | | `OPENPOST_ENCRYPTION_KEY` | A second, independent `openssl rand -base64 32` value | | `OPENPOST_DISABLE_REGISTRATIONS` | `true` after creating the first administrator, or `false` | Generate each secret with `openssl rand -base64 32` and keep both stable across restarts and restores. 4. Deploy, then verify readiness: ```sh curl https://post.example.com/api/v1/ready ``` Expect `"status":"ready"` and `"database":"ok"`. If it fails, inspect the service logs and confirm that all three URL variables use the same public origin. Open the app and create the first account. It becomes the instance administrator. Set `OPENPOST_DISABLE_REGISTRATIONS=true` afterward if you do not want public signups. The service stores SQLite and media in the `openpost_data` volume. #### Updates and backups Pin `image:` to a release tag. To upgrade, change the tag and redeploy, then check `/api/v1/ready`. Back up the `openpost_data` volume and environment values first, and record the current image tag. Keep backups private and off the server. A rollback may require the backup made for the previous version. Follow the [maintenance checklist](https://openpo.st/docs/self-hosting/maintenance.md). #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Back up your instance](https://openpo.st/docs/self-hosting/maintenance.md) before relying on it for scheduled posts. ### Email delivery Source: [https://openpo.st/docs/self-hosting/email.md](https://openpo.st/docs/self-hosting/email.md) Self-hosted OpenPost can start without an email service. Add one before you depend on password resets, workspace invitations, email notifications, or required signup verification. Pick one of the transports below and use a sender address on a domain you control. #### SMTP Get the host, port, login, and TLS mode from your mail provider. Add them to the server `.env` file: ```dotenv OPENPOST_EMAIL_PROVIDER=smtp OPENPOST_SMTP_HOST=smtp.example.com OPENPOST_SMTP_PORT=587 OPENPOST_SMTP_USERNAME=mailer OPENPOST_SMTP_PASSWORD=replace-me OPENPOST_EMAIL_FROM="OpenPost " OPENPOST_SMTP_TLS_MODE=starttls ``` Use port 465 with `OPENPOST_SMTP_TLS_MODE=tls` when your provider uses implicit TLS. OpenPost rejects unencrypted SMTP to non-loopback hosts. If the provider requires a different certificate hostname, set `OPENPOST_SMTP_SERVER_NAME` to the name on the certificate. #### Resend Verify a sending domain in Resend, then create a key with Sending access. Set a sender on the verified domain: ```dotenv OPENPOST_EMAIL_PROVIDER=resend OPENPOST_EMAIL_FROM="OpenPost " OPENPOST_RESEND_API_KEY=your-resend-key ``` #### Cloudflare Email Service Onboard your domain in Cloudflare Email Sending and create an API token with Email Sending permission. OpenPost uses the Cloudflare REST API, so it needs the account ID and token: ```dotenv OPENPOST_EMAIL_PROVIDER=cloudflare OPENPOST_EMAIL_FROM="OpenPost " OPENPOST_CLOUDFLARE_EMAIL_ACCOUNT_ID=your-account-id OPENPOST_CLOUDFLARE_EMAIL_API_TOKEN=your-api-token ``` #### Verify delivery 1. Run `docker compose up -d` after editing `.env`. 2. Invite a test address to a workspace or request a password reset for an account you control. Check both the inbox and your mail provider's delivery log. 3. Only after delivery works, set `OPENPOST_EMAIL_VERIFICATION_REQUIRED=true` if new password accounts must verify their address, then recreate the container again. If mail does not arrive, check `docker compose logs --tail=100 openpost`, the provider's sender verification, credentials, SMTP TLS mode, and the recipient's spam folder. An accepted send is not proof the message reached the inbox. Delivery callbacks, when configured for a supported provider, use `POST /api/v1/email/delivery/webhook` and `OPENPOST_EMAIL_DELIVERY_WEBHOOK_SECRET`. ### Self-host OpenPost Source: [https://openpo.st/docs/self-hosting/index.md](https://openpo.st/docs/self-hosting/index.md) This guide runs one OpenPost container with SQLite and local media storage. It is the shortest path for a personal or small-team instance. OpenPost runs its web and background work in the same container, so you do not need a separate queue service. #### Before you start - Install Docker with the Compose plugin. Run the commands below on the server that will host OpenPost. - The published image supports `linux/amd64`. Other architectures need amd64 emulation. - For a public instance, point a domain at the server and put an HTTPS reverse proxy in front of port `8080`. Forward all app requests, including `/api/v1/` and `/media/`. Provider callbacks and media URLs must be reachable from outside your network. You can test locally first. Set the final public URLs before connecting social accounts. #### Install with Docker Compose Create the data directories first: ```sh mkdir -p openpost/data/db openpost/data/media cd openpost ``` Create `.env` with fresh secrets: ```sh cat > .env <:8080` and create the first account. It becomes the instance administrator. #### Before connecting providers Replace the three local URLs with your [public HTTPS addresses](https://openpo.st/docs/self-hosting/reverse-proxy.md), then import the updated definition. Keep the `openpost_data` volume. Confirm readiness through the public address before connecting providers: ```sh curl https://post.example.com/api/v1/ready ``` #### Update and back up Use a versioned image tag from GitHub Releases. Before changing it, stop OpenPost and back up the `openpost_data` volume with the edited Compose file. Import the updated definition, then check `/api/v1/ready`. Keep backups private and off the device. A rollback may require the backup made for the previous version because database migrations are not always backward compatible. See [Maintenance](https://openpo.st/docs/self-hosting/maintenance.md) for the restore checklist. #### Next steps - [Configure integrations](https://openpo.st/docs/self-hosting/integrations/index.md) for your social platforms. - [Back up your instance](https://openpo.st/docs/self-hosting/maintenance.md) before relying on it for scheduled posts. ## API ### API reference Source: [https://openpo.st/docs/api-reference/index.md](https://openpo.st/docs/api-reference/index.md) Use the HTTP API when your own app or script needs to read OpenPost data or manage publications. Start with a token, make one read request, then use the endpoint pages for the fields and responses of the operation you need. Requests and responses use JSON. #### Base URL For Hosted, use `https://app.openpo.st/api/v1`. For a self-hosted instance, append `/api/v1` to your public OpenPost origin. #### Authentication Use a browser session for interactive work or a bearer API token for automation: ```http Authorization: Bearer YOUR_TOKEN ``` Create and revoke tokens in **Settings → Personal → Developer**. Choose both its permissions, such as `api:read` or `api:write`, and whether it can access the current workspace or all your workspaces. Use only the access your integration needs. Copy the token when it is created. OpenPost shows it once. Set an expiry and store it in your automation's secret store. Revoke it from the same settings page when it is no longer needed. #### Try a read request Set `OPENPOST_TOKEN` in your shell to the token you created, then list the workspaces it can access. Replace the origin if you self-host: ```sh curl https://app.openpo.st/api/v1/workspaces \ -H "Authorization: Bearer $OPENPOST_TOKEN" \ -H "Accept: application/json" ``` The response lists workspaces this token can access. Use one of their IDs when an endpoint asks for a workspace ID. OpenPost checks access again on every private operation. #### Understand an error | Status | What to check | | ------ | ----------------------------------------------------------------------------------------------------------------- | | `401` | Send a valid bearer token. Create a new token if it expired or was revoked. | | `403` | Check both the token's permissions and its workspace access. Some operations also depend on your account or plan. | | `404` | Check the endpoint path and resource ID. Use IDs returned by the same OpenPost instance. | | `422` | Compare the request with the endpoint schema, including required fields, formats, and allowed values. | Read the error body before retrying. A successful request that queues a publication means OpenPost accepted the work; it does not mean the provider has published it. Check the publication's destination statuses for the final result. #### Find an endpoint Browse the generated endpoint pages: - List workspaces - List publications - Create a publication - Schedule a publication - List connected accounts The machine-readable contract is available at [`/openapi.json`](https://openpo.st/docs/openapi.json). Generate clients from that file instead of copying request or response schemas into another document. For everyday scripting, skip the raw HTTP and use the [TypeScript SDK](https://openpo.st/docs/automate/sdk/index.md).