From 1f2875f50ccc9ef17712138f08e7335c0732665d Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:32:55 -0300 Subject: [PATCH 1/6] docs: multiple social accounts per network MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cap on how many accounts a workspace connects on one network is now a setting rather than a fact, and several pages stated it as a fact. - social-accounts: replaces "Connection limits (Cloud only)" with a section covering both modes, spells out which platform pairs share a network, and adds a reconnect section — reconnecting is now bound to one card, so the messages it can answer with are worth knowing - configuration: documents ALLOW_MULTIPLE_SOCIAL_ACCOUNTS and its fallback - list-social-accounts: warns that `platform` is no longer unique in the response, so integrations must key on `id` - youtube: the channel picker is gone; the channel comes from Google's screen - telegram: a reconnect has to be confirmed from the card's own channel, and no longer claims you can always connect as many channels as you like - facebook / instagram: pickers leave out what is already connected - instagram / linkedin: both networks are one card with a chooser, not two buttons — the old flow had been gone for a while - plans-and-billing: notes that the two LinkedIn and Instagram flavours share one network slot Adds a self-hosting Upgrading page. The release ships a migration that merges duplicate identities and deletes rows to make room for a new unique index, it runs unattended, and it is one-way — that needed somewhere to live, and the two places that tell you to run `migrate --force` now point at it. --- .../endpoint/list-social-accounts.mdx | 6 ++ docs.json | 3 +- knowledge-base/plans-and-billing.mdx | 2 + knowledge-base/social-accounts.mdx | 46 ++++++++++++--- platforms/facebook.mdx | 2 +- platforms/instagram.mdx | 14 +++-- platforms/linkedin.mdx | 18 +++--- platforms/telegram.mdx | 8 ++- platforms/youtube.mdx | 4 +- self-hosting/configuration.mdx | 24 ++++++++ self-hosting/docker.mdx | 4 ++ self-hosting/installation.mdx | 4 ++ self-hosting/upgrading.mdx | 59 +++++++++++++++++++ 13 files changed, 170 insertions(+), 24 deletions(-) create mode 100644 self-hosting/upgrading.mdx diff --git a/api-reference/endpoint/list-social-accounts.mdx b/api-reference/endpoint/list-social-accounts.mdx index db5744f..d28b1bf 100644 --- a/api-reference/endpoint/list-social-accounts.mdx +++ b/api-reference/endpoint/list-social-accounts.mdx @@ -8,6 +8,12 @@ description: "List all connected social accounts for the current workspace, orde Plain array of social account objects. Each item has these fields: + + **`platform` is not unique.** A workspace can hold several accounts on the same network, so more than one item may share the same `platform` value — two `"linkedin"` entries, for example. Key your integration on `id`, never on `platform`. + + This applies to any instance where [multiple accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network) are allowed, which is the default for self-hosted. Use `display_name` or `username` to tell two accounts of the same platform apart. + + Social account UUID. diff --git a/docs.json b/docs.json index b6d6c6e..411c3f8 100644 --- a/docs.json +++ b/docs.json @@ -254,7 +254,8 @@ "pages": [ "self-hosting/configuration", "self-hosting/ai", - "self-hosting/production" + "self-hosting/production", + "self-hosting/upgrading" ] } ] diff --git a/knowledge-base/plans-and-billing.mdx b/knowledge-base/plans-and-billing.mdx index 444979a..0a72001 100644 --- a/knowledge-base/plans-and-billing.mdx +++ b/knowledge-base/plans-and-billing.mdx @@ -26,6 +26,8 @@ Pricing is localized in some regions (for example, **R$60 / month** in Brazil). Each workspace connects one account on every supported network (Instagram, Facebook, LinkedIn, X, TikTok, YouTube, Pinterest, Threads, Bluesky, Mastodon, Telegram, Discord) and runs them from a single calendar. +A LinkedIn profile and a LinkedIn Page count as **one** network between them, as do Instagram Standalone and Instagram (Facebook Business) — see [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). + To manage another brand or client, or a second account on the same network, add another workspace. Each workspace is billed at the same per-workspace price, and AI credits from every workspace are pooled across your account. ## Trial diff --git a/knowledge-base/social-accounts.mdx b/knowledge-base/social-accounts.mdx index aab2a9b..d0bee54 100644 --- a/knowledge-base/social-accounts.mdx +++ b/knowledge-base/social-accounts.mdx @@ -31,21 +31,35 @@ Social accounts are the connections between TryPost and your social media profil Go to **Accounts** in the dashboard and click the platform you want to connect. For most platforms, you'll be redirected to their authorization page. A few have extra steps: -- **LinkedIn Page** — after authorizing, pick which company page to connect +- **LinkedIn** — one card covers both your personal profile and the company pages you administer. After authorizing, pick which identity to connect - **Facebook** — after authorizing, pick which page to manage -- **Instagram (Standalone)** — uses Instagram's own OAuth flow; suitable for personal IG accounts -- **Instagram (Facebook Business)** — authorize through Facebook, then pick the Instagram account linked to a Facebook page (required for first-party publishing of feed/reels/stories/carousels) -- **YouTube** — authorize with Google, then pick the channel +- **Instagram** — one card offers both connection methods. **Standalone** uses Instagram's own OAuth (suitable for personal IG accounts); **Facebook Business** authorizes through Facebook and then picks the Instagram account linked to a page (required for first-party publishing of feed/reels/stories/carousels) +- **YouTube** — authorize with Google; the channel comes from the account you pick on Google's own screen - **Bluesky** — enter your handle and an [App Password](https://bsky.app/settings/app-passwords) (not your main password) - **Mastodon** — enter your instance URL first, then authorize on that instance - **Telegram** — add the TryPost bot as an admin to your channel or group, then post the `/connect` command shown in the dialog - **Discord** — authorize TryPost and choose which server to add the bot to (requires *Manage Server*); the whole server connects as one account and you pick the channel on each post -## Connection limits (Cloud only) + + Where a platform asks you to pick (LinkedIn identities, Facebook pages, Instagram accounts), anything already connected to this workspace is left out of the list — you can only pick something new. If nothing is left, TryPost says so instead of showing an empty picker. + -On TryPost Cloud, each workspace connects one account on every supported network (its social set). To connect a second account on the same network, add another workspace. +## How many accounts per network -Self-hosted instances have no cap. +Some platforms have two flavours that count as **one network**: + +- LinkedIn profile and LinkedIn Page +- Instagram Standalone and Instagram (Facebook Business) + +**On TryPost Cloud**, each workspace connects one account per network. To manage a second account on the same network, add another workspace. + +**On self-hosted instances**, the cap is a setting. See [`ALLOW_MULTIPLE_SOCIAL_ACCOUNTS`](/self-hosting/configuration#multiple-accounts-per-network) — it defaults to whatever `SELF_HOSTED` is, so a standard self-hosted install allows several accounts on the same network out of the box. + +When several are allowed, each network's tile grows a **Connect another** card. Every connected account keeps its own card, its own name, and its own toggle in a post's Schedule tab. + + + The same account can never be connected twice, even where multiple accounts are allowed — including across the two flavours of one network. Authorizing an Instagram account you already connected through Facebook (or the other way round) is refused rather than duplicated. + ## Active vs. inactive @@ -83,6 +97,24 @@ If any of these detects a disconnected or expired account, the workspace owner r - **Permission revoked** — You manually revoked TryPost's access in the platform's settings. - **Platform policy** — The platform may revoke tokens for inactivity or policy changes. +## Reconnecting an account + +A card that needs attention shows a **Reconnect** button. Reconnecting refreshes that specific card — it keeps its posts, its scheduling history, and its place in your automations. It never creates a second card. + +Because it is tied to one card, you have to authorize **the same account** you are reconnecting: + +| What you'll see | What happened | What to do | +|---|---|---| +| *That is a different account. Authorize the one you are reconnecting.* | You signed in as someone else during the reconnect | Sign out of the platform, then reconnect and authorize the original account | +| *Page not found.* | The company page you are reconnecting is not administered by the login you used | Authorize with the account that administers that page | +| *Every account on this login is already connected.* | Everything this login offers is already connected to the workspace | Nothing to do — the account is already there | +| *This workspace already has an account for this network. Disconnect it first.* | The network's single slot is taken | Disconnect the existing account, or use another workspace | +| *Another connection is still finishing. Please try again in a moment.* | Two connections to the same network overlapped | Wait a moment and try again | + + + On Telegram, a reconnect must be confirmed **from the same channel or group** the card points at. Posting the `/connect` command somewhere else is rejected — and the code is not consumed, so you can still post it in the right place. + + ## Token security - Access tokens and refresh tokens are **encrypted at rest** using Laravel's encryption diff --git a/platforms/facebook.mdx b/platforms/facebook.mdx index 070318d..5816d8e 100644 --- a/platforms/facebook.mdx +++ b/platforms/facebook.mdx @@ -13,7 +13,7 @@ TryPost supports posting to Facebook pages. 1. Go to **Accounts** in the TryPost dashboard 2. Click **Connect Facebook** 3. Authorize TryPost on Facebook -4. Select the page you want to manage +4. Select the page you want to manage. Pages already connected to this workspace are left out of the list, and if only one is left TryPost connects it without asking ## Supported content types diff --git a/platforms/instagram.mdx b/platforms/instagram.mdx index ac50776..3a1d241 100644 --- a/platforms/instagram.mdx +++ b/platforms/instagram.mdx @@ -13,23 +13,29 @@ TryPost supports two Instagram connection flavors, each backed by a different OA | **Instagram (Standalone)** | `instagram` | Personal Instagram accounts that aren't linked to a Facebook page. Uses Instagram's own OAuth. | | **Instagram (Facebook Business)** | `instagram-facebook` | Business or Creator accounts linked to a Facebook page. Required for first-party publishing of feed, reels, and stories at full quality. | -Connect either (or both) from **Accounts** in the dashboard. +Both are reached from the single **Instagram** card on the **Accounts** page, which asks which method you want. + + + The two count as **one network**, so they share the same slot. On TryPost Cloud that means one Instagram account per workspace, by either method. See [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). + + The same Instagram account cannot be connected through both methods — authorizing one that is already connected the other way is refused rather than duplicated. + ## Connect your account ### Standalone (personal) 1. Go to **Accounts** in the TryPost dashboard -2. Click **Connect Instagram** +2. Click **Connect** on the **Instagram** card, then choose **Instagram** 3. Authorize TryPost on instagram.com 4. The account shows up immediately ### Business (via Facebook) 1. Go to **Accounts** in the TryPost dashboard -2. Click **Connect Instagram (Facebook Business)** +2. Click **Connect** on the **Instagram** card, then choose **Instagram (Facebook Business)** 3. Authorize TryPost through Facebook -4. Select the Facebook page whose Instagram account you want to connect +4. Select the Facebook page whose Instagram account you want to connect. Accounts already connected to this workspace are left out of the list ## Supported content types diff --git a/platforms/linkedin.mdx b/platforms/linkedin.mdx index b841aaf..3ff45fe 100644 --- a/platforms/linkedin.mdx +++ b/platforms/linkedin.mdx @@ -10,18 +10,20 @@ TryPost supports posting to LinkedIn personal profiles and company pages. ## Connect your account -### Personal profile +A single **LinkedIn** card covers both your personal profile and the company pages you administer — there is no separate "Connect LinkedIn Page" button. 1. Go to **Accounts** in the TryPost dashboard -2. Click **Connect LinkedIn** -3. Authorize TryPost on LinkedIn — your profile is connected directly, no extra picker needed +2. Click **Connect** on **LinkedIn** +3. Authorize TryPost on LinkedIn +4. Pick what to connect on the **Select a LinkedIn identity** screen: your personal profile, or one of the Pages you administer -### Company page +Each identity connects as its own social account. Repeat the flow to add another — anything already connected to this workspace is left out of the picker. -1. Go to **Accounts** and click **Connect LinkedIn Page** -2. Authorize TryPost on LinkedIn with organization admin scope -3. TryPost loads every Page you administer and redirects you to a dedicated **Select a LinkedIn Page** screen -4. Pick the Page you want to schedule for. Each Page connects as its own social account — repeat the flow to add more. + + Profile and Page count as **one network**, so they share the same slot. On TryPost Cloud that means one LinkedIn account per workspace; a standard self-hosted install allows both. See [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). + + Connecting a second identity means authorizing again, which is normal — LinkedIn keeps both tokens valid as long as TryPost asks for the same permissions each time. + ## Supported content types diff --git a/platforms/telegram.mdx b/platforms/telegram.mdx index 8fb08a7..4e1f035 100644 --- a/platforms/telegram.mdx +++ b/platforms/telegram.mdx @@ -20,7 +20,13 @@ TryPost publishes to Telegram **channels and groups** through a shared TryPost b The bot must be an **administrator** of the channel. Telegram only delivers channel posts (including the `/connect` command and reactions) to bots that are admins, and the bot needs admin rights to publish. -You can connect as many channels and groups as you like — each one becomes its own account. +Each channel or group becomes its own account. How many you can connect depends on [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network) your instance allows — one on TryPost Cloud, several on a standard self-hosted install. + +## Reconnecting a channel + +A channel that lost its connection shows a **Reconnect** button, which issues a fresh `/connect` code. Post that code **in the same channel the card points at** — a reconnect is tied to one card and will not move it to a different chat. + +Posting it somewhere else is rejected with *Post the command in the channel you are reconnecting*. The code is **not** consumed, so you can still post the same one in the right channel. ## Supported content types diff --git a/platforms/youtube.mdx b/platforms/youtube.mdx index 8996a9e..d20604c 100644 --- a/platforms/youtube.mdx +++ b/platforms/youtube.mdx @@ -12,8 +12,8 @@ TryPost supports uploading YouTube Shorts. 1. Go to **Accounts** in the TryPost dashboard 2. Click **Connect YouTube** -3. Authorize TryPost with your Google account -4. Select the YouTube channel to connect +3. Authorize TryPost with your Google account, choosing the channel on Google's own screen +4. The channel shows up immediately — TryPost connects the one that authorization was granted for ## Supported content types diff --git a/self-hosting/configuration.mdx b/self-hosting/configuration.mdx index 21cafaf..805560c 100644 --- a/self-hosting/configuration.mdx +++ b/self-hosting/configuration.mdx @@ -42,6 +42,30 @@ SELF_HOSTED=true There's no reason to flip this to `false` on a self-hosted install. The Cloud SaaS deployment is the only place that runs with billing enabled. +## Multiple accounts per network + +```env +ALLOW_MULTIPLE_SOCIAL_ACCOUNTS=true +``` + +Controls whether a workspace can connect more than one account on the same social network — two LinkedIns, two Instagrams, and so on. `.env.example` and the Docker compose file ship with it set to `true`. + +Two flavours of the same platform count as **one network**, so they share the slot: + +- LinkedIn profile + LinkedIn Page +- Instagram Standalone + Instagram (Facebook Business) + +| Value | Behaviour | +|---|---| +| `true` | A workspace may connect several accounts on the same network. Each network's tile gains a **Connect another** card | +| `false` | One account per network. A second one is refused with *This workspace already has an account for this network* | + + + When the variable is unset it falls back to `SELF_HOSTED`, so instances that upgrade without touching `.env` keep allowing multiple accounts. This is deliberately independent of `SELF_HOSTED` so it can be flipped on its own. + + +The same account is never connected twice, whatever the value — reconnecting an identity that already has a card updates that card instead of adding another, including across the two flavours of one network. + ## Database TryPost supports PostgreSQL and MySQL. diff --git a/self-hosting/docker.mdx b/self-hosting/docker.mdx index 96e434e..9c3ac1c 100644 --- a/self-hosting/docker.mdx +++ b/self-hosting/docker.mdx @@ -159,6 +159,10 @@ docker compose -f compose.prod.yaml exec app php artisan migrate --force docker compose -f compose.prod.yaml down ``` + + Running `migrate --force` to move an existing instance to a newer version? Back the database up first and check [Upgrading](/self-hosting/upgrading) — some releases rewrite data as well as schema. + + --- ## Local development diff --git a/self-hosting/installation.mdx b/self-hosting/installation.mdx index 539916a..9a5bae1 100644 --- a/self-hosting/installation.mdx +++ b/self-hosting/installation.mdx @@ -86,6 +86,10 @@ Also configure **mail** (invites / password reset) and optional social OAuth / A php artisan migrate --force ``` + + On a fresh install this just builds the schema. When you run it later to **upgrade** an existing instance, back the database up first and check [Upgrading](/self-hosting/upgrading) — some releases rewrite data as well as schema. + + ### 5. Passport keys (and local storage symlink) Passport needs an RSA key pair on disk to **sign and verify** API / MCP tokens: diff --git a/self-hosting/upgrading.mdx b/self-hosting/upgrading.mdx new file mode 100644 index 0000000..7b18926 --- /dev/null +++ b/self-hosting/upgrading.mdx @@ -0,0 +1,59 @@ +--- +title: "Upgrading" +description: "What to check before pulling a new version of TryPost" +--- + +## The routine + +Whatever version you are coming from, an upgrade is: + +```bash +git pull +composer install --no-dev --optimize-autoloader +npm ci && npm run build +php artisan migrate --force +php artisan config:cache && php artisan route:cache && php artisan view:cache +php artisan horizon:terminate +``` + +On Docker, the same thing through the running container: + +```bash +docker compose -f compose.prod.yaml pull +docker compose -f compose.prod.yaml up -d +docker compose -f compose.prod.yaml exec app php artisan migrate --force +``` + + + **Back the database up before `migrate --force`.** Migrations run unattended and some of them rewrite data, not just schema. A dump you can restore is the only reliable way back. + + +## Release notes that need attention + +Most upgrades need nothing beyond the routine above. The ones below change data or defaults, so read them if you are crossing that version. + +### Multiple social accounts per network + +This release adds a database constraint that a workspace cannot hold the same identity twice on the same platform. + +**Why it matters:** earlier versions could store the same account more than once — the per-network guard was skipped on self-hosted installs, and Pinterest created a fresh row on every connect. Duplicates like that would block the new constraint, so the migration merges them first. + +For each duplicated identity it keeps the **most recently created** account, moves that account's scheduled posts and automation targets onto the survivor, and deletes the rest. Where a post ended up with two targets pointing at the same account, the unpublished repeats are dropped so it isn't published twice — preferring the row you had enabled. Posts already published are never touched. + +**This is one-way.** Rolling the migration back drops the constraint but does not bring the merged rows back. + +Every merge is written to your log at `warning` level with enough detail to reconstruct it: + +``` +Collapsed duplicate social accounts + workspace_id, platform, platform_user_id, + kept_id, dropped_ids, + post_platforms_repointed, post_platforms_deleted, + automations_rewritten +``` + + + Want to know what it will do before it does it? Restore a copy of your production database somewhere disposable, run `php artisan migrate --force` against the copy, and read those log lines. If nothing is logged, you have no duplicates and the migration is a no-op. + + +**New setting:** [`ALLOW_MULTIPLE_SOCIAL_ACCOUNTS`](/self-hosting/configuration#multiple-accounts-per-network) decides whether a workspace may connect several accounts on one network. You do not have to set it — when it is missing it follows `SELF_HOSTED`, so an existing self-hosted install keeps the behaviour it had. From 5ff6694fe2fee3314dcf3811ec80bca347f254f9 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:38:18 -0300 Subject: [PATCH 2/6] docs: correct three things the first pass got wrong MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checked every factual claim in this branch against the code. Three did not hold up. The upgrade page invented its own deploy sequence, which diverged from the one in Production — it was missing `event:cache`. Two copies of the same routine is how docs go stale, so it now points at the existing one and covers only what is specific to upgrading. It also blurred two different outcomes when a merge leaves a post aimed at the same account twice. One target survives only when the post has not published there yet; once it has, every unpublished repeat goes. Spelled both out, since this is a page about a migration that deletes rows. The picker note claimed TryPost always speaks up rather than showing an empty list. True when filtering leaves nothing, but it also skips the picker entirely when exactly one identity is left, which is worth knowing. --- knowledge-base/social-accounts.mdx | 2 +- self-hosting/upgrading.mdx | 30 +++++++++++++----------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/knowledge-base/social-accounts.mdx b/knowledge-base/social-accounts.mdx index d0bee54..07950cc 100644 --- a/knowledge-base/social-accounts.mdx +++ b/knowledge-base/social-accounts.mdx @@ -41,7 +41,7 @@ Go to **Accounts** in the dashboard and click the platform you want to connect. - **Discord** — authorize TryPost and choose which server to add the bot to (requires *Manage Server*); the whole server connects as one account and you pick the channel on each post - Where a platform asks you to pick (LinkedIn identities, Facebook pages, Instagram accounts), anything already connected to this workspace is left out of the list — you can only pick something new. If nothing is left, TryPost says so instead of showing an empty picker. + Where a platform asks you to pick (LinkedIn identities, Facebook pages, Instagram accounts), anything already connected to this workspace is left out of the list — you can only pick something new. If that leaves nothing to pick, TryPost tells you rather than showing an empty list, and if it leaves exactly one it connects it without asking. ## How many accounts per network diff --git a/self-hosting/upgrading.mdx b/self-hosting/upgrading.mdx index 7b18926..92dceb6 100644 --- a/self-hosting/upgrading.mdx +++ b/self-hosting/upgrading.mdx @@ -5,24 +5,13 @@ description: "What to check before pulling a new version of TryPost" ## The routine -Whatever version you are coming from, an upgrade is: - -```bash -git pull -composer install --no-dev --optimize-autoloader -npm ci && npm run build -php artisan migrate --force -php artisan config:cache && php artisan route:cache && php artisan view:cache -php artisan horizon:terminate -``` +Pull the new version, then run the same steps you already run on a deploy: -On Docker, the same thing through the running container: +- Rebuild dependencies and assets, and re-run the [optimization commands](/self-hosting/production#optimizations) +- Apply migrations with `php artisan migrate --force` +- Restart the queue workers so they pick up the new code — `php artisan horizon:terminate` lets Supervisor bring them back -```bash -docker compose -f compose.prod.yaml pull -docker compose -f compose.prod.yaml up -d -docker compose -f compose.prod.yaml exec app php artisan migrate --force -``` +On Docker, [Common production commands](/self-hosting/docker#common-production-commands) has the container equivalents. **Back the database up before `migrate --force`.** Migrations run unattended and some of them rewrite data, not just schema. A dump you can restore is the only reliable way back. @@ -38,7 +27,14 @@ This release adds a database constraint that a workspace cannot hold the same id **Why it matters:** earlier versions could store the same account more than once — the per-network guard was skipped on self-hosted installs, and Pinterest created a fresh row on every connect. Duplicates like that would block the new constraint, so the migration merges them first. -For each duplicated identity it keeps the **most recently created** account, moves that account's scheduled posts and automation targets onto the survivor, and deletes the rest. Where a post ended up with two targets pointing at the same account, the unpublished repeats are dropped so it isn't published twice — preferring the row you had enabled. Posts already published are never touched. +For each duplicated identity it keeps the **most recently created** account, moves that account's scheduled posts and automation targets onto the survivor, and deletes the rest. + +Merging can leave a post aimed at the same account twice, which would publish it twice. Those repeats are collapsed: + +- If the post has **not** published there yet, one target survives — the one you had enabled, if any +- If it **has** already published there, every unpublished repeat is removed, since the content has gone out + +Targets that already published are never deleted or altered. They record what went out, and hold the id the platform needs to manage that post later. **This is one-way.** Rolling the migration back drops the constraint but does not bring the merged rows back. From 44c16bbc9376bde1ecfab545d0890996928e4590 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:44:19 -0300 Subject: [PATCH 3/6] docs: keep the cloud reader on one story MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md already says the docs are cloud-first and that self-hosted specifics belong in a Note or the self-hosting section. This branch had not been reading it: the cap on accounts per network turned into a two-mode comparison in body prose, which makes every reader work out which half is theirs — including in api-reference, where the endpoints are documented against app.trypost.it. Cloud is the statement again. One account per network, two flavours of a network share the slot, add a workspace for a second account. Self-hosting gets a pointer at the end, matching how the rest of the knowledge base already handles it. The reconnect table also listed "Every account on this login is already connected", which only ever appears where multiple accounts are enabled — gone. Records the rule it broke in CLAUDE.md with the failing shape next to the working one, since the abstract version did not stop it. --- CLAUDE.md | 19 +++++++++++++++++++ .../endpoint/list-social-accounts.mdx | 8 +++----- knowledge-base/plans-and-billing.mdx | 2 +- knowledge-base/social-accounts.mdx | 15 ++++++--------- platforms/instagram.mdx | 2 +- platforms/linkedin.mdx | 2 +- platforms/telegram.mdx | 2 +- 7 files changed, 32 insertions(+), 18 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 073731e..e342bbc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,6 +48,25 @@ Same paths, user configures `APP_URL` in `.env`: - Default instructions assume the user is on **TryPost Cloud** - Self-hosted specifics go in ``, ``, or the Self-Hosting anchor - Example: Platform pages say "click Connect" for cloud, API credentials in `` for self-hosted +- This includes `api-reference/` — those endpoints are documented against `https://app.trypost.it/api`, so describe the Cloud response + +**When a fixed behaviour becomes configurable**, keep the Cloud value as the statement and push the setting into self-hosting. Do not rewrite body prose into a two-mode comparison — it makes every reader parse a branch that only one of them is on. + +```mdx +{/* Wrong — the Cloud reader has to work out which half applies to them */} +On TryPost Cloud each workspace connects one account per network. On +self-hosted instances the cap is a setting; see ALLOW_MULTIPLE_SOCIAL_ACCOUNTS. + +{/* Right — Cloud is the statement, self-hosting is a pointer */} +Each workspace connects one account per network. + + + Self-hosting TryPost? This cap is a setting on your instance — see + [multiple accounts per network](/self-hosting/configuration#...). + +``` + +The same applies to anything a self-hoster can switch off or raise: platform availability, limits, AI providers. State what Cloud does; link out for the knob. ### URLs in examples - API curl examples: `https://app.trypost.it/api/...` diff --git a/api-reference/endpoint/list-social-accounts.mdx b/api-reference/endpoint/list-social-accounts.mdx index d28b1bf..ad0dbbe 100644 --- a/api-reference/endpoint/list-social-accounts.mdx +++ b/api-reference/endpoint/list-social-accounts.mdx @@ -8,11 +8,9 @@ description: "List all connected social accounts for the current workspace, orde Plain array of social account objects. Each item has these fields: - - **`platform` is not unique.** A workspace can hold several accounts on the same network, so more than one item may share the same `platform` value — two `"linkedin"` entries, for example. Key your integration on `id`, never on `platform`. - - This applies to any instance where [multiple accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network) are allowed, which is the default for self-hosted. Use `display_name` or `username` to tell two accounts of the same platform apart. - + + **Key on `id`, not on `platform`.** A workspace holds one account per network, so today each `platform` appears at most once — but that is a [plan limit](/knowledge-base/social-accounts#connection-limits), not a guarantee of this endpoint. Self-hosted instances can be configured to return several accounts sharing one `platform` value. + Social account UUID. diff --git a/knowledge-base/plans-and-billing.mdx b/knowledge-base/plans-and-billing.mdx index 0a72001..f107422 100644 --- a/knowledge-base/plans-and-billing.mdx +++ b/knowledge-base/plans-and-billing.mdx @@ -26,7 +26,7 @@ Pricing is localized in some regions (for example, **R$60 / month** in Brazil). Each workspace connects one account on every supported network (Instagram, Facebook, LinkedIn, X, TikTok, YouTube, Pinterest, Threads, Bluesky, Mastodon, Telegram, Discord) and runs them from a single calendar. -A LinkedIn profile and a LinkedIn Page count as **one** network between them, as do Instagram Standalone and Instagram (Facebook Business) — see [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). +A LinkedIn profile and a LinkedIn Page count as **one** network between them, as do Instagram Standalone and Instagram (Facebook Business) — see [connection limits](/knowledge-base/social-accounts#connection-limits). To manage another brand or client, or a second account on the same network, add another workspace. Each workspace is billed at the same per-workspace price, and AI credits from every workspace are pooled across your account. diff --git a/knowledge-base/social-accounts.mdx b/knowledge-base/social-accounts.mdx index 07950cc..426ac3b 100644 --- a/knowledge-base/social-accounts.mdx +++ b/knowledge-base/social-accounts.mdx @@ -44,21 +44,19 @@ Go to **Accounts** in the dashboard and click the platform you want to connect. Where a platform asks you to pick (LinkedIn identities, Facebook pages, Instagram accounts), anything already connected to this workspace is left out of the list — you can only pick something new. If that leaves nothing to pick, TryPost tells you rather than showing an empty list, and if it leaves exactly one it connects it without asking. -## How many accounts per network +## Connection limits -Some platforms have two flavours that count as **one network**: +Each workspace connects one account per network. To manage a second account on the same network, add another workspace. + +Two platforms count as **one network** when they are two ways into the same place, so they share that single slot: - LinkedIn profile and LinkedIn Page - Instagram Standalone and Instagram (Facebook Business) -**On TryPost Cloud**, each workspace connects one account per network. To manage a second account on the same network, add another workspace. - -**On self-hosted instances**, the cap is a setting. See [`ALLOW_MULTIPLE_SOCIAL_ACCOUNTS`](/self-hosting/configuration#multiple-accounts-per-network) — it defaults to whatever `SELF_HOSTED` is, so a standard self-hosted install allows several accounts on the same network out of the box. - -When several are allowed, each network's tile grows a **Connect another** card. Every connected account keeps its own card, its own name, and its own toggle in a post's Schedule tab. +Connecting one of a pair uses up the network's slot, so a workspace holds either a LinkedIn profile or a LinkedIn Page, not both. - The same account can never be connected twice, even where multiple accounts are allowed — including across the two flavours of one network. Authorizing an Instagram account you already connected through Facebook (or the other way round) is refused rather than duplicated. + Self-hosting TryPost? This cap is a setting on your instance — see [multiple accounts per network](/self-hosting/configuration#multiple-accounts-per-network). ## Active vs. inactive @@ -107,7 +105,6 @@ Because it is tied to one card, you have to authorize **the same account** you a |---|---|---| | *That is a different account. Authorize the one you are reconnecting.* | You signed in as someone else during the reconnect | Sign out of the platform, then reconnect and authorize the original account | | *Page not found.* | The company page you are reconnecting is not administered by the login you used | Authorize with the account that administers that page | -| *Every account on this login is already connected.* | Everything this login offers is already connected to the workspace | Nothing to do — the account is already there | | *This workspace already has an account for this network. Disconnect it first.* | The network's single slot is taken | Disconnect the existing account, or use another workspace | | *Another connection is still finishing. Please try again in a moment.* | Two connections to the same network overlapped | Wait a moment and try again | diff --git a/platforms/instagram.mdx b/platforms/instagram.mdx index 3a1d241..5bde79d 100644 --- a/platforms/instagram.mdx +++ b/platforms/instagram.mdx @@ -16,7 +16,7 @@ TryPost supports two Instagram connection flavors, each backed by a different OA Both are reached from the single **Instagram** card on the **Accounts** page, which asks which method you want. - The two count as **one network**, so they share the same slot. On TryPost Cloud that means one Instagram account per workspace, by either method. See [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). + The two count as **one network** and share a single slot, so a workspace connects one Instagram account by either method — not one of each. See [connection limits](/knowledge-base/social-accounts#connection-limits). The same Instagram account cannot be connected through both methods — authorizing one that is already connected the other way is refused rather than duplicated. diff --git a/platforms/linkedin.mdx b/platforms/linkedin.mdx index 3ff45fe..e405ad4 100644 --- a/platforms/linkedin.mdx +++ b/platforms/linkedin.mdx @@ -20,7 +20,7 @@ A single **LinkedIn** card covers both your personal profile and the company pag Each identity connects as its own social account. Repeat the flow to add another — anything already connected to this workspace is left out of the picker. - Profile and Page count as **one network**, so they share the same slot. On TryPost Cloud that means one LinkedIn account per workspace; a standard self-hosted install allows both. See [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network). + Profile and Page count as **one network** and share a single slot, so a workspace connects one or the other, not both. See [connection limits](/knowledge-base/social-accounts#connection-limits). Connecting a second identity means authorizing again, which is normal — LinkedIn keeps both tokens valid as long as TryPost asks for the same permissions each time. diff --git a/platforms/telegram.mdx b/platforms/telegram.mdx index 4e1f035..c2fd1bf 100644 --- a/platforms/telegram.mdx +++ b/platforms/telegram.mdx @@ -20,7 +20,7 @@ TryPost publishes to Telegram **channels and groups** through a shared TryPost b The bot must be an **administrator** of the channel. Telegram only delivers channel posts (including the `/connect` command and reactions) to bots that are admins, and the bot needs admin rights to publish. -Each channel or group becomes its own account. How many you can connect depends on [how many accounts per network](/knowledge-base/social-accounts#how-many-accounts-per-network) your instance allows — one on TryPost Cloud, several on a standard self-hosted install. +Each channel or group becomes its own account, and a workspace connects one of them. To run a second channel, add another workspace — see [connection limits](/knowledge-base/social-accounts#connection-limits). ## Reconnecting a channel From 192585996ead15c1c89906860cffe2b292ae6bae Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:46:04 -0300 Subject: [PATCH 4/6] docs: say the api reference covers self-hosted too, and what it cannot do MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The self-hosting configuration page never told you the API reference applies to your instance. It does — same routes, same payloads, same MCP tools. What differs is the base URL and that responses follow the settings on that page rather than the Cloud plan, multiple accounts per network being the one you can actually see in a response. With that written down where a self-hoster reads it, the note on the endpoint goes back to being a cloud statement. Also says there that accounts are connected from the dashboard: every platform needs a browser to authorize, so the API only lists and toggles. Worth stating on the endpoint people reach for when looking for a way to add one. --- api-reference/endpoint/list-social-accounts.mdx | 4 +++- self-hosting/configuration.mdx | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/api-reference/endpoint/list-social-accounts.mdx b/api-reference/endpoint/list-social-accounts.mdx index ad0dbbe..1d9c88e 100644 --- a/api-reference/endpoint/list-social-accounts.mdx +++ b/api-reference/endpoint/list-social-accounts.mdx @@ -9,9 +9,11 @@ description: "List all connected social accounts for the current workspace, orde Plain array of social account objects. Each item has these fields: - **Key on `id`, not on `platform`.** A workspace holds one account per network, so today each `platform` appears at most once — but that is a [plan limit](/knowledge-base/social-accounts#connection-limits), not a guarantee of this endpoint. Self-hosted instances can be configured to return several accounts sharing one `platform` value. + **Read accounts by `id`, not by `platform`.** A workspace holds [one account per network](/knowledge-base/social-accounts#connection-limits), so each `platform` appears at most once — but that is a plan limit, not a guarantee of this endpoint. +Accounts are connected from the dashboard, since every platform needs a browser to authorize. The API reads them and can toggle one [active or inactive](/api-reference/endpoint/toggle-social-account); it cannot add or remove one. + Social account UUID. diff --git a/self-hosting/configuration.mdx b/self-hosting/configuration.mdx index 805560c..5e5b8f7 100644 --- a/self-hosting/configuration.mdx +++ b/self-hosting/configuration.mdx @@ -135,6 +135,8 @@ Alternatively, set `PASSPORT_PRIVATE_KEY` and `PASSPORT_PUBLIC_KEY` in `.env` (P MCP clients authenticate with OAuth (`mcp:use`), not with an API key Bearer header. API keys are for the REST API only. +The [API reference](/api-reference/introduction) describes your instance too — same routes, same payloads, same MCP tools. Only two things differ: the base URL is your `APP_URL` followed by `/api`, and responses reflect the settings on this page rather than the Cloud plan. The most visible one is [multiple accounts per network](#multiple-accounts-per-network) — where it is on, `GET /social-accounts` can return several accounts sharing one `platform` value, so read it by `id`. + Full install order: [Installation](/self-hosting/installation). From d81043943ba46f0bbc14a26bf0d4ad2862ee0fb5 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:48:55 -0300 Subject: [PATCH 5/6] docs: fix a contradiction and two more cloud-only claims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading the branch as a whole rather than edit by edit turned up three things. The LinkedIn page told you to repeat the flow to add another identity, three lines above a note saying a workspace holds one or the other. The first was left over from the two-mode draft. The picker note claimed identities already connected get filtered out of the list. True of the code, invisible on Cloud: the connect card only renders when the network is empty, so there is never anything to filter. Rewrote it around what a Cloud reader actually meets — a picker that only appears when there is a choice — and dropped the same claim from the Facebook and Instagram steps. It also said a single available identity connects without a picker. That holds for Facebook, Instagram and YouTube, not for LinkedIn, which always shows its identity screen even when the profile is the only thing on it. --- knowledge-base/social-accounts.mdx | 2 +- platforms/facebook.mdx | 2 +- platforms/instagram.mdx | 2 +- platforms/linkedin.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/knowledge-base/social-accounts.mdx b/knowledge-base/social-accounts.mdx index 426ac3b..ed94007 100644 --- a/knowledge-base/social-accounts.mdx +++ b/knowledge-base/social-accounts.mdx @@ -41,7 +41,7 @@ Go to **Accounts** in the dashboard and click the platform you want to connect. - **Discord** — authorize TryPost and choose which server to add the bot to (requires *Manage Server*); the whole server connects as one account and you pick the channel on each post - Where a platform asks you to pick (LinkedIn identities, Facebook pages, Instagram accounts), anything already connected to this workspace is left out of the list — you can only pick something new. If that leaves nothing to pick, TryPost tells you rather than showing an empty list, and if it leaves exactly one it connects it without asking. + Facebook and Instagram only show their page picker when there is something to choose between — administer a single page and TryPost connects it without asking. If the login has nothing to offer, it says so rather than showing an empty list. LinkedIn always shows its identity screen, even when your profile is the only thing on it. ## Connection limits diff --git a/platforms/facebook.mdx b/platforms/facebook.mdx index 5816d8e..ada9d64 100644 --- a/platforms/facebook.mdx +++ b/platforms/facebook.mdx @@ -13,7 +13,7 @@ TryPost supports posting to Facebook pages. 1. Go to **Accounts** in the TryPost dashboard 2. Click **Connect Facebook** 3. Authorize TryPost on Facebook -4. Select the page you want to manage. Pages already connected to this workspace are left out of the list, and if only one is left TryPost connects it without asking +4. Select the page you want to manage. If you administer only one, TryPost connects it without asking ## Supported content types diff --git a/platforms/instagram.mdx b/platforms/instagram.mdx index 5bde79d..ab5729d 100644 --- a/platforms/instagram.mdx +++ b/platforms/instagram.mdx @@ -35,7 +35,7 @@ Both are reached from the single **Instagram** card on the **Accounts** page, wh 1. Go to **Accounts** in the TryPost dashboard 2. Click **Connect** on the **Instagram** card, then choose **Instagram (Facebook Business)** 3. Authorize TryPost through Facebook -4. Select the Facebook page whose Instagram account you want to connect. Accounts already connected to this workspace are left out of the list +4. Select the Facebook page whose Instagram account you want to connect. If only one of your pages has one, TryPost connects it without asking ## Supported content types diff --git a/platforms/linkedin.mdx b/platforms/linkedin.mdx index e405ad4..42d00b4 100644 --- a/platforms/linkedin.mdx +++ b/platforms/linkedin.mdx @@ -17,7 +17,7 @@ A single **LinkedIn** card covers both your personal profile and the company pag 3. Authorize TryPost on LinkedIn 4. Pick what to connect on the **Select a LinkedIn identity** screen: your personal profile, or one of the Pages you administer -Each identity connects as its own social account. Repeat the flow to add another — anything already connected to this workspace is left out of the picker. +Each identity connects as its own social account. Profile and Page count as **one network** and share a single slot, so a workspace connects one or the other, not both. See [connection limits](/knowledge-base/social-accounts#connection-limits). From f51d26658fce12d335d168124c309ac72aabfc07 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Tue, 25 Aug 2026 07:52:54 -0300 Subject: [PATCH 6/6] docs: the faq still described the old connect behaviour "If you try to connect an account that's already connected, TryPost will update the existing connection" was true when a connect upserted by identity. It no longer is: the network's slot is taken while an account sits in it, so there is no connect button to press. Refreshing an account is Reconnect, which the FAQ now points at. --- knowledge-base/social-accounts.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knowledge-base/social-accounts.mdx b/knowledge-base/social-accounts.mdx index ed94007..87df830 100644 --- a/knowledge-base/social-accounts.mdx +++ b/knowledge-base/social-accounts.mdx @@ -130,7 +130,7 @@ Go to **Accounts**, find the account, and click **Disconnect**. This: - No. Each social media account can only be connected once per workspace. If you try to connect an account that's already connected, TryPost will update the existing connection. + No. Each social media account is connected once per workspace, and its network's slot is taken while it is — so there is nothing to click to add it again. To refresh an account you already have, use [Reconnect](#reconnecting-an-account) on its card, which updates that card rather than creating another. Posts scheduled for a disconnected account will fail for that platform when the scheduled time arrives. Other platforms in the same post are not affected. You'll receive a notification about the failure.