# Shoutrrr Documentation --- # Introduction > Shoutrrr is the open-source, self-hostable alternative to Buffer, Typefully & Hootsuite. Write once, publish everywhere. Shoutrrr is a social media scheduling tool you run yourself. Connect your accounts, draft a post once, and send it to every network at the same time — or queue it to go out on a recurring schedule. No monthly seat fees, and no third party holding your tokens or your data. It's built for individuals and teams: invite collaborators into a shared workspace, keep clients or brands separated, and see how your posts perform — all from a single, fast interface. ## Why Shoutrrr - **You own everything** — your posts, your audience tokens, your analytics, all on your own infrastructure. - **One post, every platform** — compose once and publish to multiple accounts, tweaking the text per network when you want. - **Plan ahead** — a posting queue with recurring time slots and a month calendar keep your feed consistent without babysitting it. - **Made for teams** — workspaces, roles, and email invites keep clients and collaborators tidy. - **No lock-in** — open source under Apache 2.0, runs anywhere Docker does. ## Supported platforms | Platform | Connect with | Limits per post | Threads | | --------------- | ---------------- | -------------------------- | ---------------- | | **X** (Twitter) | OAuth 2.0 | ≤280 chars, up to 4 media | Yes | | **Bluesky** | ATProto OAuth (or app password) | ≤300 graphemes, up to 4 images | Yes | | **LinkedIn** | OAuth 2.0 (OIDC) | ≤3000 chars, up to 9 images | Single post | | **Facebook** | OAuth 2.0 | ≤63,206 chars, up to 10 media | Single post | | **Instagram** | OAuth 2.0 | ≤2200 chars, up to 10 media | Single post | | **Threads** | OAuth 2.0 | ≤500 chars, up to 10 media | Yes | | **Discord** | Webhook | ≤2000 chars, up to 10 media | Auto-split | When a post is too long for a platform that supports threads, Shoutrrr splits it into a thread automatically. Each target publishes independently and retries on failure. ## Core features - **Composer** — draft with media and alt text, with a live per-network character count. - **Multi-account publishing** — fan one post out to many accounts at once, with optional per-platform overrides. - **Queue & calendar** — recurring posting slots in your workspace's timezone, plus a month calendar to review everything. Publish instantly whenever you like. - **Analytics** — follower and post-count trends per account, plus per-post engagement (likes, reposts, replies, impressions). - **Workspaces & team** — multiple workspaces with role-based memberships, email invitations, and ownership transfer. - **Secure by default** — email/password with verification, two-factor (TOTP), passkeys (WebAuthn), and optional social login. Account tokens are stored encrypted and refreshed automatically. - **AI-ready** — a built-in MCP server lets assistants draft, schedule, and (with your confirmation) publish, scoped to a single workspace. ## Next steps - [Self-hosting](/docs/getting-started) — get an instance running with Docker. - [Connecting accounts](/docs/connecting-accounts) — link X, Bluesky, LinkedIn, Meta, and Discord. - [Configuration](/docs/configuration) — environment variables and tuning. - [MCP server](/docs/mcp) — connect AI assistants to your instance. --- # Self-hosting > Run your own Shoutrrr instance with Docker in a few minutes. The recommended way to host Shoutrrr is the prebuilt Docker image. It runs the web app, queue worker, and scheduler in a single container — ideal for a single box. It defaults to SQLite with no external services, and you can switch to Postgres/Redis later if you need to scale out. :::tip Prefer not to run it yourself? **Shoutrrr Cloud** is a fully managed option at $10/mo — sign up at [app.shoutrrr.com](https://app.shoutrrr.com). ::: ```bash docker pull ghcr.io/coollabsio/shoutrrr:latest ``` ## Quick start with `docker run` Create a production env file: ```bash cat > .env.prod <<'EOF' APP_URL=http://localhost:8080 APP_KEY=base64:PASTE_GENERATED_KEY_HERE EOF ``` Generate an `APP_KEY` and paste it into `.env.prod`: ```bash docker run --rm --entrypoint php ghcr.io/coollabsio/shoutrrr:latest \ /var/www/html/artisan key:generate --show ``` Start Shoutrrr with persistent volumes: ```bash docker volume create shoutrrr-storage docker volume create shoutrrr-sqlite docker run -d \ --name shoutrrr \ --env-file .env.prod \ -p 8080:8080 \ -v shoutrrr-storage:/var/www/html/storage \ -v shoutrrr-sqlite:/var/www/html/database/sqlite \ ghcr.io/coollabsio/shoutrrr:latest ``` Shoutrrr runs its startup tasks automatically, including database migrations. Open `http://localhost:8080`, register the first account, and you're in. :::tip To test a specific release, replace `latest` with a version tag such as `1.0.0-rc.2` in the commands above. ::: ## Going to production For a real public deployment: - Set `APP_URL` to your HTTPS domain. - Set `SESSION_SECURE_COOKIE=true`. - Keep `APP_ENV=production` and `APP_DEBUG=false`. If you serve Shoutrrr through a TLS-terminating reverse proxy (Coolify/Traefik, Nginx, Caddy, Cloudflare Tunnel…), also set `TRUSTED_PROXIES=*` and `OCTANE_HTTPS=true` so redirects, OAuth callbacks, and assets use `https://` instead of `http://`. See [Reverse proxies & HTTPS](/docs/configuration#reverse-proxies--https). :::warning Keep your `APP_KEY` safe and stable. It encrypts your stored account tokens — if you lose or change it, connected accounts will need to be re-linked. ::: ## Docker Compose If you prefer Compose, use the bundled production file, which pulls the prebuilt image from GHCR: ```bash git clone https://github.com/coollabsio/shoutrrr.git cd shoutrrr cp .env.example.prod .env # Set APP_KEY and APP_URL in .env before starting. docker compose -f docker-compose.production.yaml run --rm app \ php artisan key:generate --show docker compose -f docker-compose.production.yaml up -d ``` ## Deploy with Coolify [Coolify](https://coolify.io) deploys Shoutrrr straight from the repository using the bundled Compose file — it handles the domain, HTTPS, and persistent volumes for you. 1. In Coolify, choose **+ New → Resource → Public Repository** and enter `https://github.com/coollabsio/shoutrrr`. 2. Set the **Build Pack** to **Docker Compose** and the file to `docker-compose.production.yaml`. 3. Under the `app` service, add a **Domain** pointing at port **8080**. Coolify provisions TLS automatically. 4. Add `APP_KEY`, `APP_URL` (matching the domain), `APP_ENV=production`, and `APP_DEBUG=false` as environment variables — plus any account credentials (see [Connecting accounts](/docs/connecting-accounts)). 5. Because Coolify terminates TLS at its proxy, also add `TRUSTED_PROXIES=*`, `OCTANE_HTTPS=true`, and `SESSION_SECURE_COOKIE=true` so links and OAuth callbacks use HTTPS (see [Reverse proxies & HTTPS](/docs/configuration#reverse-proxies--https)). 6. Click **Deploy**. The Compose file declares named volumes for storage and the SQLite database, so your data and uploads survive redeploys. :::warning On standard Coolify installs, the `coolify-proxy` (Traefik) container already binds host port **8080**. If your Compose file publishes `8080:8080` on the host (e.g. an older copy of `docker-compose.production.yaml`), deployment fails with a port-in-use error. Let Coolify route to the container via the **Domain** you set above instead of publishing the port — or remap the host side to a free port such as `8081:8080`. You do not need to publish a host port for Coolify to reach the app. ::: ## Resetting test data ```bash docker rm -f shoutrrr docker volume rm shoutrrr-storage shoutrrr-sqlite ``` --- # Connecting accounts > Link your X, Bluesky, LinkedIn, Meta (Facebook, Instagram, Threads), and Discord accounts so Shoutrrr can publish on your behalf. Shoutrrr publishes through your own accounts. Bluesky works out of the box — no developer app or credentials — thanks to ATProto OAuth, and Discord works without a developer app too. X, LinkedIn, and the Meta networks (Facebook, Instagram, Threads) publish through apps you register, so they need a few credentials in your environment. :::warning Publishing and scheduling rely on a running queue worker and scheduler. The provided Docker setups start both for you automatically. ::: ## Bluesky Bluesky connects over **ATProto OAuth** — the recommended method — with nothing to configure. There's no developer app to register and no client ID or secret to set: Shoutrrr publishes its own OAuth client-metadata document from your instance, and the DPoP signing key is generated and stored automatically on first use. From the **Connected accounts** screen, click **Connect Bluesky**, enter your handle (e.g. `you.bsky.social`) or leave it blank to pick your account on Bluesky, then authorize. To connect an account on a self-hosted PDS or another ATProto service, open **Advanced** and set the **Service URL**. :::note OAuth requires your instance to be reachable at its real, public `APP_URL` over HTTPS — Bluesky's authorization server fetches your client-metadata and JWKS documents directly from that URL during the handshake. If you run behind a reverse proxy, make sure the [HTTPS settings](/docs/configuration#reverse-proxies--https) are correct so the generated `client_id` and callback URLs use `https://`. ::: ### App passwords (fallback) If OAuth isn't an option, you can connect with a Bluesky [app password](https://bsky.app/settings/app-passwords) instead — open **Use app password** on the connect dialog. This is **not recommended**: app passwords bypass two-factor authentication, and disconnecting the account in Shoutrrr does not revoke the password on Bluesky — manage those from Bluesky's app-password settings. ## X (Twitter) Register an app at [developer.x.com](https://developer.x.com) and add its credentials to your `.env`. The redirect URI must match what you register; it defaults to `${APP_URL}/accounts/callback/x`. ```dotenv X_CLIENT_ID= X_CLIENT_SECRET= X_REDIRECT_URI="${APP_URL}/accounts/callback/x" ``` ## LinkedIn Register an app at [linkedin.com/developers](https://www.linkedin.com/developers). In the app's **Products** tab, add both of these products: - [Sign In with LinkedIn using OpenID Connect](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2) — provides the `openid`, `profile`, and `email` scopes. - [Share on LinkedIn](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin) — provides the `w_member_social` scope required to publish posts. Shoutrrr requests all four scopes when connecting an account. If either product is missing, LinkedIn may show only a generic **Bummer, something went wrong** error during authorization. Add the app credentials to your `.env`. The redirect URI defaults to `${APP_URL}/accounts/callback/linkedin` and must also be listed under the app's authorized redirect URLs. ```dotenv LINKEDIN_CLIENT_ID= LINKEDIN_CLIENT_SECRET= LINKEDIN_REDIRECT_URI="${APP_URL}/accounts/callback/linkedin" ``` ## Facebook & Instagram Facebook and Instagram are both powered by a **single Meta app**. Register one at [developers.facebook.com](https://developers.facebook.com), add Facebook Login, and share its credentials with your `.env`. The redirect URI defaults to `${APP_URL}/accounts/callback/meta` — register that exact value on the app. ```dotenv FACEBOOK_CLIENT_ID= FACEBOOK_CLIENT_SECRET= FACEBOOK_REDIRECT_URI="${APP_URL}/accounts/callback/meta" FACEBOOK_GRAPH_VERSION=v25.0 ``` When connecting, you pick which Facebook **Page** to publish as. To connect an **Instagram** account, that Page must have a linked Instagram [Professional (Business) account](https://help.instagram.com/502981923235522) — a Page without one can't be connected as Instagram. :::note To publish for accounts other than your own test users, Meta requires **App Review** and **Business Verification** on the app, with the relevant `pages_*` and `instagram_*` permissions approved. ::: ## Threads Threads uses a **separate Meta app** from Facebook and Instagram. Create a Threads app at [developers.facebook.com](https://developers.facebook.com) with the Threads API use case, then add its credentials. The redirect URI defaults to `${APP_URL}/accounts/callback/threads`. ```dotenv THREADS_CLIENT_ID= THREADS_CLIENT_SECRET= THREADS_REDIRECT_URI="${APP_URL}/accounts/callback/threads" ``` ## Discord No developer app or environment variables required. In Discord, open **Server Settings → Integrations → Webhooks**, create a webhook for the channel you want to post to, and copy its **Webhook URL**. Paste that URL on the **Connected accounts** screen to link the channel. Shoutrrr only accepts official Discord webhook URLs (`discord.com` or `discordapp.com`, including the `canary`/`ptb` subdomains). Posts longer than Discord's 2000-character limit are split automatically across multiple messages. ## Optional: social login Let people sign in with a social account instead of a password: ```dotenv SOCIALITE_ENABLED=true SOCIALITE_PROVIDERS=google # comma-separated: google,x,linkedin GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GOOGLE_REDIRECT_URI="${APP_URL}/auth/google/callback" ``` :::note After editing `.env`, restart the container so the new values are picked up. Make sure each redirect URI registered with the provider exactly matches your `APP_URL`. ::: --- # Configuration > Environment variables for tuning your Shoutrrr instance. Shoutrrr is configured through environment variables in your `.env` file (or `--env-file` / Compose environment). The defaults run a self-contained instance on SQLite with no external services. This page covers the variables you're most likely to change. ## Application | Variable | Default | Description | | ----------------------- | ------------------------ | -------------------------------------------------------- | | `APP_KEY` | — | Secret that encrypts stored account tokens. **Required.** | | `APP_URL` | `http://localhost:8080` | Public URL of your instance. Used for OAuth redirects. | | `APP_ENV` | `production` (image) | `production` or `local`. | | `APP_DEBUG` | `false` | Verbose errors. Keep `false` in production. | | `SESSION_SECURE_COOKIE` | `false` | Set `true` when serving over HTTPS. | :::warning Generate `APP_KEY` once and keep it stable — changing it invalidates every encrypted account token, forcing all accounts to be re-linked. ::: ## Reverse proxies & HTTPS If you run Shoutrrr behind a TLS-terminating proxy — Coolify/Traefik, Nginx, Caddy, a Cloudflare Tunnel, etc. — the container receives plain HTTP and only learns the request was really HTTPS from forwarded headers. Without the variables below, Shoutrrr generates `http://` links: OAuth callbacks fail with redirect-URI mismatches (e.g. LinkedIn), post-login redirects break, and the browser blocks assets as **mixed content**. | Variable | Default | Description | | ----------------- | ------- | -------------------------------------------------------------------------------------------- | | `TRUSTED_PROXIES` | — | Trust forwarded headers. Set `*` to trust all proxies, or a comma-separated CIDR list. | | `OCTANE_HTTPS` | `false` | Force HTTPS scheme generation for redirects and asset URLs. Set `true` behind an HTTPS proxy. | For a typical HTTPS deployment behind a proxy: ```bash APP_URL=https://your-domain.example.com SESSION_SECURE_COOKIE=true TRUSTED_PROXIES=* OCTANE_HTTPS=true ``` - `TRUSTED_PROXIES` makes Shoutrrr honour `X-Forwarded-Proto` / `X-Forwarded-Host` for per-request scheme, host, and client-IP detection. - `OCTANE_HTTPS` forces the HTTPS scheme so links generated under Octane stay `https://` across requests — this is what clears mixed-content errors and the HTTP login-redirect problem. :::note Only set `TRUSTED_PROXIES=*` when Shoutrrr is genuinely reachable solely through your proxy. If the container is exposed directly, restrict it to the proxy's IP range so clients can't spoof forwarded headers. ::: ## Workers Publishing and scheduling require a queue worker and the scheduler. The Docker image runs both inside the container by default. | Variable | Default | Description | | ------------------------ | ------- | -------------------------------------------- | | `QUEUE_WORKER_ENABLED` | `true` | Run the in-container queue worker. | | `SCHEDULER_ENABLED` | `true` | Run the in-container scheduler. | | `INERTIA_SSR_ENABLED` | `false` | Enable server-side rendering. | :::note To run the worker and scheduler as separate services (e.g. in the cloud), set `QUEUE_WORKER_ENABLED=false` / `SCHEDULER_ENABLED=false` and start them with `php artisan queue:work` and `php artisan schedule:work` in their own containers. ::: ## Database, cache & queue By default everything is database-backed on SQLite — no extra services to run. | Variable | Default | Description | | ------------------ | ------------------------------------ | -------------------------------------- | | `DB_CONNECTION` | `sqlite` | `sqlite`, `pgsql`, or `mysql`. | | `DB_DATABASE` | `database/sqlite/database.sqlite` | SQLite path, or database name. | | `DB_HOST` / `DB_PORT` | `127.0.0.1` / `3306` | For Postgres/MySQL. | | `DB_USERNAME` / `DB_PASSWORD` | — | For Postgres/MySQL. | | `CACHE_STORE` | `database` | e.g. `database` or `redis`. | | `QUEUE_CONNECTION` | `database` | e.g. `database` or `redis`. | | `SESSION_DRIVER` | `database` | Where sessions are stored. | To scale out, point `DB_*` / `REDIS_*` at managed services and switch `DB_CONNECTION`, `CACHE_STORE`, and `QUEUE_CONNECTION` to use them. ## Email Email is used for verification and team invitations. | Variable | Default | Description | | ------------------- | -------------------- | ------------------------------------ | | `MAIL_MAILER` | `log` | `smtp`, `log`, etc. | | `MAIL_HOST` / `MAIL_PORT` | `127.0.0.1` / `2525` | SMTP server. | | `MAIL_FROM_ADDRESS` | `hello@example.com` | Sender address for outgoing mail. | ## Accounts & social login Credentials for connecting and publishing to networks are documented in [Connecting accounts](/docs/connecting-accounts) — `X_*`, `LINKEDIN_*`, and the optional `SOCIALITE_*` / `GOOGLE_*` variables for social sign-in. --- # MCP server > Let AI assistants draft, schedule, and publish Shoutrrr posts through the built-in Model Context Protocol server. Every Shoutrrr instance ships with a built-in [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server. Point an MCP-capable assistant — Claude, Cursor, or anything that speaks MCP — at your instance and it can read your posts and analytics, draft and edit content, manage schedules and account sets, and (with your explicit confirmation) publish on your behalf. The server runs inside your own deployment. Nothing is sent to a third party: the assistant connects directly to your instance and acts as you, scoped to a single workspace. ## Endpoint The server is exposed over streamable HTTP at `/mcp`: ``` https://your-domain.example/mcp ``` It's protected by OAuth 2.1. Most clients only need that URL — they discover the authorization endpoints automatically from the standard metadata documents: - `/.well-known/oauth-protected-resource` - `/.well-known/oauth-authorization-server` Dynamic client registration is supported, so you don't have to pre-register the assistant as an app. :::warning The MCP server requires a logged-in Shoutrrr account and inherits all the same permissions, so only expose it over HTTPS. The OAuth flow encrypts and issues bearer tokens that act on your behalf. ::: ## Connecting an assistant Add the endpoint to your client. For example, with the Claude Code CLI: ```bash claude mcp add --transport http shoutrrr https://your-domain.example/mcp ``` Or, for a client that takes a JSON config: ```json { "mcpServers": { "shoutrrr": { "type": "http", "url": "https://your-domain.example/mcp" } } } ``` The first time the assistant connects, it opens Shoutrrr's OAuth consent screen in your browser: 1. **Sign in** to Shoutrrr if you aren't already. 2. **Pick a workspace.** The consent screen lists every workspace you belong to. The one you choose is bound to this connection. 3. **Approve.** The assistant receives a token and is ready to use. :::note The chosen workspace is **fixed for the life of the connection**. To operate on a different workspace, reconnect (re-run the OAuth flow) and pick another one. The `list-workspaces-tool` shows which workspace the current connection is bound to, plus your other workspaces. ::: ## Permissions and safety The MCP server never grants more than the web UI does. - **Same roles, same policies.** Every tool call is authorized against the exact workspace policies the web app uses. If your role can't do something in the browser, the assistant can't do it either. - **Membership is re-checked on every call.** If you're removed from (or leave) the bound workspace, the connection stops working immediately — even though the token hasn't expired. - **Irreversible actions need confirmation.** Outward-facing or destructive tools — publishing now, retrying a failed target, and deleting a post — refuse to run unless called with `confirm=true`. A well-behaved assistant will ask you first and only then confirm. :::tip Publishing is asynchronous. After a publish or retry, the assistant should poll `get-post-tool` to see per-target results rather than assume success. ::: ## What the assistant can do The server exposes the following tools. Names are the on-the-wire identifiers your client will show. ### Reading | Tool | What it does | | --- | --- | | `list-workspaces-tool` | Show the bound workspace plus your other workspaces. | | `list-posts-tool` | List posts in the workspace; optionally filter by status or a text query. | | `get-post-tool` | Fetch one post by id, including per-target publish status and attempts. | | `get-calendar-tool` | List scheduled and published posts for a calendar month (`YYYY-MM`). | | `list-connected-accounts-tool` | List connected X, LinkedIn, and Bluesky accounts and their status. | | `list-account-sets-tool` | List saved account sets (named groups of accounts). | | `get-posting-schedule-tool` | Get the workspace timezone and recurring weekly posting slots. | ### Drafting and editing | Tool | What it does | | --- | --- | | `create-post-tool` | Create a draft. Destination is `all` (every account), `set` (an account set), or `account` (one account). | | `update-post-tool` | Edit text, destination, per-account overrides, and attached media. Uses optimistic concurrency — see below. | | `add-post-media-tool` | Attach an image by downloading it from a public URL (jpeg, png, webp, gif; max 8 MiB). Returns a media id. | | `remove-post-media-tool` | Remove an image from the workspace media library by id. | ### Scheduling and publishing | Tool | What it does | | --- | --- | | `schedule-post-tool` | Schedule a post for a specific ISO-8601 time. Pass `null` to un-schedule back to draft. | | `queue-post-tool` | Schedule a post into the next open slot of the workspace posting schedule. | | `publish-post-tool` | Publish immediately. Irreversible and outward-facing — requires `confirm=true`. | | `retry-post-target-tool` | Retry a failed publish target. Outward-facing — requires `confirm=true`. | ### Account sets and sharing | Tool | What it does | | --- | --- | | `create-account-set-tool` | Create a named, reusable group of connected accounts. | | `update-account-set-tool` | Rename a set or change its member accounts. | | `delete-account-set-tool` | Delete a set (existing posts that used it are unaffected). | | `create-share-link-tool` | Create a public, no-auth URL for a post. | | `list-shares-tool` | List active (non-revoked, non-expired) share links for a post. | | `delete-share-tool` | Revoke a share link. | ### Deleting | Tool | What it does | | --- | --- | | `delete-post-tool` | Delete a post. A draft is removed permanently; a published post is also deleted from the connected accounts where possible. Irreversible — requires `confirm=true`. | :::note **Editing safely.** `update-post-tool` uses optimistic concurrency: pass the `expected_updated_at` value returned by `get-post-tool`. If the post changed in the meantime, the call returns a stale-write error instead of clobbering the newer version. Re-fetch and retry. ::: ## Tokens and rate limits - **Token lifetime.** Access tokens expire after 8 hours; refresh tokens after 30 days. Compliant clients refresh automatically, so you rarely re-consent. - **Rate limit.** MCP requests are throttled to 60 per minute per user. The OAuth authorize and token endpoints are throttled separately to curb consent abuse. - **Cleanup.** Abandoned and orphaned workspace bindings are pruned hourly, so revoking a token or deleting a client leaves nothing behind. ## Troubleshooting - **"This connection is not bound to a workspace."** The OAuth grant lost its workspace binding (for example, the token was created out of band). Reconnect and pick a workspace on the consent screen. - **"You do not have permission…"** Your role in the bound workspace doesn't allow that action, or you've been removed from the workspace. Check your membership. - **A publish "succeeded" but nothing appeared.** Publishing is asynchronous and per-target. Call `get-post-tool` and inspect each target's status and attempts; failed targets can be retried with `retry-post-target-tool`. --- # API > Automate Shoutrrr from your own code. Create, schedule, and publish posts over a REST API. Shoutrrr exposes a REST API so you can create, schedule, and publish posts — and manage the accounts they go to — from your own code. It's the same surface the app uses, so anything you can do in the UI you can do over HTTP. Every request and response is JSON, over HTTPS. The base URL is: ``` https://app.shoutrrr.com/api/v1 ``` Looking for AI-assistant access instead of writing code? See the [MCP server](/docs/mcp) — it wraps this same functionality for tools like Claude and Cursor. Use the API when you're scripting; use MCP when an assistant acts on your behalf. ## Authentication The API authenticates with a bearer token. Send it in the `Authorization` header on every request: ``` Authorization: Bearer ``` Create a token from your Shoutrrr account settings (**Settings → API tokens**). A request without a valid token returns `401 Unauthenticated`. :::warning Treat tokens like passwords — they act on your account with your permissions. Only send them over HTTPS, never commit them to source control, and revoke any token you suspect has leaked. ::: ## Quickstart **Create a draft post.** Send `base_text` and a `destination` (`all`, a `set`, or a single `account`). The response contains the new post's `id`. ```bash curl -X POST 'https://app.shoutrrr.com/api/v1/posts' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "base_text": "Hello from the API", "destination": { "kind": "all" } }' ``` **Publish it.** Publishing is asynchronous — the API returns `202 Accepted` immediately and processes each target in the background. ```bash curl -X POST 'https://app.shoutrrr.com/api/v1/posts//publish' \ -H 'Authorization: Bearer ' ``` **Poll for status.** Fetch the post to watch each target move through `publishing` → `published` (or `failed`). ```bash curl 'https://app.shoutrrr.com/api/v1/posts/' \ -H 'Authorization: Bearer ' ``` Prefer to schedule instead of publish now? `POST /posts/{id}/schedule` with a `scheduled_at` timestamp, or `POST /posts/{id}/queue` to drop it into the next open posting-schedule slot. ## Pagination List endpoints (`/posts`, `/account-sets`, `/connected-accounts`, a post's `/shares`) are cursor-paginated. Each response carries a `pagination` object: To walk every page, pass the returned `next_cursor` back as the `cursor` query parameter until `has_more` is `false`: ```bash curl 'https://app.shoutrrr.com/api/v1/posts?per_page=50&cursor=' \ -H 'Authorization: Bearer ' ``` ## Errors Errors use standard HTTP status codes and a JSON body with a human-readable `message`. Validation errors (`422`) additionally include a field-keyed `errors` map: ```json { "message": "The name field is required.", "errors": { "name": ["The name field is required."] } } ``` | Status | Meaning | | --- | --- | | `401` | Missing or invalid bearer token. | | `403` | Authenticated, but not allowed to perform this action. | | `404` | The resource (post, target, share) doesn't exist. | | `409` | Edit conflict — the post changed since you loaded it (see below). | | `422` | Validation failed; inspect `errors` for per-field messages. | **Optimistic concurrency.** When updating a post, pass the `expected_updated_at` you last saw. If someone else changed the post in the meantime, the API returns `409 Conflict` instead of silently overwriting their edit — re-fetch, reconcile, and retry. **Async publishing.** `publish` and `retry` return `202 Accepted` with the post in a `publishing` state. Poll `GET /posts/{id}` and read each target's `status`, `error_kind`, and `error_message` to track progress. Only failed targets can be retried, via `POST /posts/{id}/targets/{targetId}/retry`. ## Endpoint reference Full request and response schemas for every endpoint, grouped by resource: - [Posts](/docs/api/posts) — create, read, update, delete - [Post actions](/docs/api/post-actions) — schedule, queue, publish, retry - [Account sets](/docs/api/account-sets) - [Connected accounts](/docs/api/connected-accounts) - [Media](/docs/api/media) - [Calendar](/docs/api/calendar) - [Posting schedule](/docs/api/posting-schedule) - [Shares](/docs/api/shares) --- # Posts > Create, read, update, and delete posts and their per-platform targets. --- # Post actions > Schedule, queue, publish, and retry posts. --- # Account sets > Group connected accounts so a post can target them in one shot. --- # Connected accounts > List the social accounts connected to your workspace. --- # Media > Upload and remove images and videos used in posts. --- # Calendar > Fetch posts for a given month. --- # Posting schedule > Read the recurring posting-slot schedule. --- # Shares > Create and revoke shareable preview links for a post. --- # Changelog > Shoutrrr releases, pulled from GitHub. ## v1.5.0 — September 20, 2026 v1.5.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.5.0 A minor release that adds cross-platform sync pipelines, so a source account can automatically repost new content to multiple destination accounts across platforms. Also fixes exact scheduled date/time display in post live status, corrects the Instagram DM scope identifier, and stops over-rotating Bluesky single-use refresh tokens. ## ✨ Additions - **sync:** cross-platform sync pipelines that fan out a source account's posts to multiple destination accounts across platforms, with native repost detection to avoid duplicate reposts (#180) ## 🐛 Fixes - **posts:** show the exact scheduled date and time in a post's live status instead of a relative approximation (#177) - **accounts:** correct the Instagram DM scope identifier so DM connections request the right permission (#178) - **publishing:** stop over-rotating Bluesky single-use refresh tokens, preventing crash-window `invalid_grant` failures that flipped healthy accounts to needs-attention (#175) ## 🔧 Maintenance - **deps:** update all Composer and bun dependencies to their latest versions, including Laravel 13.32, Passport 13.8, Socialite 5.31, phpseclib 4, Pest 5, TypeScript 7, and Vitest 5 (86308ed) - **deps:** bump the github-actions group with 3 updates (#174) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.4.4...v1.5.0 --- ## v1.4.4 — August 24, 2026 v1.4.4 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.4.4 A patch release that makes desktop MCP OAuth clients easier to connect, fixes calendar date handling and post creation, validates X video aspect ratios before publishing, restores API key creation under FrankenPHP/Octane, and prevents transient token-refresh failures from disabling accounts. ## ✨ Additions - **mcp:** allow configurable OAuth redirect domains and custom URI schemes such as `cursor://`, so desktop MCP clients can complete dynamic client registration (#161) ## 🐛 Fixes - **publishing:** treat 429, 5xx, and timeout responses during token refresh as retryable, preventing refresh sweeps and publish jobs from marking healthy accounts as needing attention; increase the per-account refresh lock from 60 to 120 seconds (#173) - **api:** generate Passport RSA keys directly instead of invoking a console command that is unavailable under FrankenPHP/Octane, restoring automatic key generation during API key creation and cleaning up partial writes (#172) - **calendar:** open the composer when clicking any non-past day, including days that already have posts, while keeping post, overflow, and drag interactions from creating unwanted drafts (#171) - **publishing:** validate X's 1:3 to 3:1 video aspect-ratio limit in composer and server prechecks, classify failed video processing as a terminal validation error, and surface X's processing error (#170) - **posts:** compare calendar cells using scheduling-timezone date keys, fixing off-by-one today/past highlighting in month and agenda views and making relative dates timezone-aware (#169) ## 🔧 Maintenance - **mcp:** log the first redirect URI submitted during OAuth client registration to help diagnose callback configuration (e0b896c) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.4.3...v1.4.4 --- ## v1.4.3 — August 9, 2026 v1.4.3 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.4.3 A small patch release that corrects the monthly X post quota so it reflects typical per-post pricing. ## 🐛 Fixes - **billing:** derive the monthly X post limit from the pricing map's standard `POST` operation weight instead of the worst-case `xPublishCostMicrousd()` cost, so the quota reflects typical post pricing (e.g. ~333 posts for the default budget instead of 25). The monthly budget cap still guards against expensive posts (URLs, high-cost ops), so spend is unaffected — only the enforced/displayed post count changes (#160) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.4.2...v1.4.3 --- ## v1.4.2 — August 9, 2026 v1.4.2 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.4.2 A patch release that hardens Bluesky publishing and the post queue, and adds Discord mentions plus KLIPY attribution to the composer. ## ✨ Additions - **posts:** add a dedicated Discord mention picker with a plain-text ⇄ mention toggle and User/Role/Channel selection, composing native `<@id>`/`<@&id>`/`<#id>` markup and rendering resolved labels in previews and published posts. Also renders LinkedIn company annotations (`@[Name](urn:li:organization:ID)`) as linked names (#156) - **compose:** add KLIPY's required attribution to the GIF picker — a fixed "Search KLIPY" placeholder and a "Powered by KLIPY" link below results (#157) ## 🐛 Fixes - **publishing:** serialize Bluesky app-password token refresh behind a per-account cache lock (re-reading the session inside the lock) so concurrent publish/engagement/DM/repost jobs no longer race on the single-use `refreshJwt` and trip Bluesky's rate limit; bound Bluesky HTTP calls with timeouts and fall back to the persisted session on lock timeout (#158) - **publishing:** derive whether a Bluesky OAuth refresh needs a `private_key_jwt` assertion from the stored `client_id` instead of the request host, fixing `invalid_client` failures behind a reverse proxy that flipped healthy accounts to needs-attention (#158) - **posts:** derive `mentions.*.handles.*` validation rules from the `Platform` enum so Laravel's `excludeUnvalidatedArrayKeys` no longer silently strips Discord mention markup before it reaches the draft (#156) - **queue:** surface a rolling runway of the next 10 open slots (scanning up to 90 days) instead of a fixed 14-day window, so sparser schedules don't run out of visible queue slots; switch the queue slot picker to the shadcn `Select` for visual consistency (#153, fixes #143) - **gifs:** scope the media mixing-rule guard to the target thread segment via `mediaForSegment`, so media in one segment no longer blocks attaching a GIF or clip to another (#151) ## 🔒 Security - **deps:** bump `league/commonmark` to 2.9.0 to resolve newly-published DoS and unsafe-link-bypass advisories (transitive via `laravel/framework`) (#157) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.4.1...v1.4.2 --- ## v1.4.1 — August 5, 2026 v1.4.1 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.4.1 A patch release that clears two v1.4.0 regressions: the queue worker failed to start — leaving every post stuck at "publishing" — and shipped images reported a stale version number. ## 🐛 Fixes - **docker:** spawn the queue worker from a script instead of an inline supervisord command, so it actually starts — posts no longer stick at "publishing" on v1.4.0 (a6d8d36) - **release:** derive the app version from the published git tag so a shipped image can no longer drift from its release (#149) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.4.0...v1.4.1 --- ## v1.4.0 — August 5, 2026 v1.4.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.4.0 A big composer- and messaging-focused release: a unified DM inbox across four platforms with media attachments, a GIF/sticker/clip browser, per-thread media in the composer, an auto-repost/boost pipeline, LinkedIn Page support, and a fresh icon set and gradient design pass — plus a round of publishing, pagination, and OAuth fixes. ## ✨ Features ### Messaging - **messages:** unified DM inbox for X, Bluesky, Instagram & Facebook (#131) - **messaging:** send media attachments in direct messages (#136) ### Composer & posts - **gifs:** GIF/sticker/clip browser (#133) - **compose:** attach media to individual thread posts (#138) - **compose:** toggle to select/deselect all accounts (#142) - **posts:** "copy as draft" action for posts (#139) - **calendar:** multi-account glyph stack on posts (#128) ### Platforms & publishing - **linkedin:** LinkedIn Page support (#117) - **repost:** auto-repost/boost pipeline for X, LinkedIn & Bluesky (#124) - **x:** premium account detection & video length limits (#83) ### UI & design - **ui:** Cloudflare Kumo-style gradient on primary surfaces (#148) - **icons:** migrate from lucide-react to hugeicons (#144) - **toast:** color toasts by intent with semantic tokens (#134) ## ⚡ Performance - **inertia:** lazily resolve shared props and poll only changed keys (#135) ## 🐛 Fixes - **publish:** recover orphaned queue redeliveries instead of failing (#147) - **compose:** calibrate GD decode limit and surface upload errors (#146) - **posts:** fix cursor pagination crash on page 2 of the posts feed (#145) - **image-editor:** compress composed exports to avoid upload 422s (#129) - **healthcheck:** use a curl-based healthcheck against the app's route (#132) - **mentions:** persist handle edits on saved mentions (#130) - **security:** allow Cursor MCP OAuth callbacks in CSP form-action (#120) - **inertia:** fix OAuth authorization navigation (#121) - **vite:** support LAN HMR and HTTPS tunnels (4ce113c) ## 🔧 Maintenance - **ci:** speed up the test workflow (#118) - **deps:** bump docker/login-action (#137) and actions/checkout (#125) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.1...v1.4.0 ## 🎉 New Contributors - @eugenepyvovarov made their first contribution in #83 - @mkantem made their first contribution in #121 - @kitlord made their first contribution in #132 --- ## v1.3.1 — July 21, 2026 v1.3.1 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.1 A focused follow-up to v1.3.0: an analytics summary redesign, a per-request/external-lookup caching pass, and a handful of publishing and composer fixes across Meta, Threads, and the post editor. ## ✨ Features - **analytics:** summary stat tiles and redesigned follower chart (#116) ## ⚡ Performance - **perf:** cache expensive per-request and external lookups (#111) ## 🐛 Fixes - **meta:** handle duplicate OAuth callbacks (471bd8e) - **threads:** fail deletes rejected by the Graph API (ce2766c) - **posts:** proxy media through a same-origin endpoint for editors (#113) - **feedback:** prevent screenshot capture failure on cross-origin images (#112) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.0...v1.3.1 --- ## v1.3.0 — July 19, 2026 v1.3.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0 The largest release yet: full Meta platform support (Facebook, Instagram, Threads), Discord webhooks, a public HTTP API, an engagement inbox with reply triage, workspace subscriptions with usage metering and X cost budgets, and a Radix → Base UI rewrite — plus a long tail of publishing, security, and Postgres-compatibility fixes. ## ✨ Features ### Platforms & publishing - **meta:** Facebook, Instagram & Threads publishing, metrics and engagement (#75) - **discord:** integration via channel webhooks (#84) - **publishing:** Reels and Stories publishing with a per-account format picker (#106) - **compose:** Facebook, Instagram & Threads compose previews (#108) - **publishing:** Instagram/Threads image conversion and fixes (#101) - **x:** opt-in quote tweets from a pasted status link (#71) - **compose:** accept more video formats via in-browser conversion (#88) ### Composer & engagement - **compose:** emoji browser — Frimousse picker + inline `:shortcode` typeahead (#73) - **compose:** `Shift+Enter` soft newline + platform-accurate blank-line preview (#72) - **compose:** show both mention modes and keep cleared handles blank (#105) - **compose:** properly refresh recent post + show media in the post list (#103) - **engagement:** emoji picker and mentions in the quick reply box (#93) - **engagement:** keyboard triage and dummy inbox seeder (df3940c) - **engagement:** persist reply conversation roots (52c7cb6) - **mentions:** resolve LinkedIn org URNs for mention tagging (#98) ### Billing, usage & metrics - **billing:** workspace subscriptions and publish gates (f77690b) - **usage:** usage metering base (#63) - **usage:** track X API cost budgets (65fb01b) - **usage:** per-workspace X budgets and reworked instance usage page (#110) - **usage:** instance usage reporting (8c75f01) - **billing:** promotion codes and tax ID collection (2c2bbf7) - **metrics:** age-banded polling with unchanged-streak backoff (#95) - **engagement:** fix X replies not loading + scale reply-fetch (#91) - **analytics:** seed demo metrics and toggle chart series (7b823fc) ### Instance & workspace administration - **instance:** enable/disable platforms in instance settings (#78) - **workspace:** enable/disable connected accounts per workspace (#79) - **engagement:** gate LinkedIn reply fetching behind a capability scope (#102) - **settings:** move workspace and instance nav into the sidebar (cb90806) - **settings:** per-platform polling controls (8f618c0) - **sidebar:** billing-aware footer + hoisted workspace settings + update indicator (#89) - **feedback:** in-app feedback widget with Discord delivery (#109) ### Platform, API & infrastructure - **api:** public HTTP API (#74) - **ui:** migrate UI from Radix to Base UI (#81) - **mcp:** add `laravel/mcp` to enhance server capabilities (04a55f7) - **storage:** configurable file storage + public images disk (ce4f0de, bbb4843) - **ci:** build and publish multi-platform (amd64/arm64) images (947e307) - **auth:** self-provision Passport encryption keys (#87) - **session:** extend default session lifetime to seven days (aba1128) - **observability:** opt-in Sentry error & performance monitoring (a92dc55) ## 🐛 Fixes - **publishing:** close precheck and connector gaps across every platform (#100) - **linkedin:** escape little-text-format reserved chars (#99) - **db:** make the schema and queries PostgreSQL-compatible (#85) - **security:** allow form redirects to any HTTPS service, incl. Stripe billing (2b08da3, 8bd2a3a) - **engagement:** stop like/unlike and reply actions from silently failing (#92) - **engagement:** only treat pasted images as images (#94) - **engagement:** fix author name truncation in reply views (#97) - **compose:** resolve 422 on edited-video upload + allow media host in CSP (#70) - **bluesky:** enforce one-GIF/no-mix rule before posting (#69) - **workspace:** prevent workspace logo distortion in the selector (3cd75d7) - **ui:** show selected label not raw value in Base UI selects (a154981) - **ui:** add `type=submit` to inert form buttons after the Base UI migration (a2996a9) - **auth:** repair email verification link and resend button (2173b31) - **accounts:** repair Discord reconnect button (dc63d27) - **sentry:** skip initialization when `window` is undefined (#96) - **x:** align publish limits and usage reporting (0adf185) - **workspaces:** enforce billing and publishing invariants (c0755ee) - **media:** survive S3 listing errors in the prune-uploads job (11ba652) - **docker:** copy generated emoji data into the production image (d90b678) - **ci:** correct jq filter for manifest digest extraction (e074645) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.2.0...v1.3.0 ## 🎉 New Contributors - @kwstasna made their first contribution in #108 --- ## v1.3.0-rc.8 — July 17, 2026 v1.3.0-rc.8 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.8 ## Features - **Post list refresh & media** — the recent-post list now refreshes properly and shows attached media inline (#103). - **LinkedIn org mentions** — mention tagging resolves LinkedIn organization URNs so org mentions render as real tags (#98). - **Age-banded metrics polling** — metrics polling is age-banded with an unchanged-streak backoff to cut redundant fetches (#95). - **LinkedIn reply capability gate** — LinkedIn reply fetching is gated behind an opt-in Community Management capability scope (#102). - **Instagram/Threads image conversion** — image conversion and related publishing fixes for Instagram and Threads (#101). ## Fixes - Closed publish-precheck and connector gaps across every platform (#100). - Escaped LinkedIn Little Text Format reserved characters so post bodies are no longer silently truncated (#99). - Fixed author-name truncation in reply views (#97). - Skipped Sentry initialization when `window` is undefined (#96). **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.0-rc.7...v1.3.0-rc.8 --- ## v1.3.0-rc.7 — July 16, 2026 v1.3.0-rc.7 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.7 ## Features - **Quick reply upgrades** — the engagement inbox reply box now has an emoji picker and @-mention support. - **Keyboard triage** — the engagement inbox supports keyboard-driven triage for faster review. - **Sidebar settings** — workspace and instance settings now live directly in the sidebar, with the settings nav flattened into direct destinations. - **Analytics chart series** — analytics charts let you toggle individual series on and off. - **Public images disk & compose polling** — added a public images storage disk and status polling while a post is composing/publishing. ## Fixes - Like/unlike and reply actions no longer fail silently when they hit an error. - Pasted content is only treated as an image when it actually is one. - Metrics and reply fetches are now skipped for disabled accounts. **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.0-rc.6...v1.3.0-rc.7 --- ## v1.3.0-rc.6 — July 15, 2026 v1.3.0-rc.6 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.6 ## Features - **Multi-platform Docker images** — production images are now built and published for both `linux/amd64` and `linux/arm64`. - **Configurable file storage** — uploads can now be pointed at a configurable storage disk (e.g. an S3-compatible bucket). - **X replies now load reliably** — fixed X engagement replies failing to load, and scaled reply fetching with an adaptive polling cadence, per-account rate-limit handling, and batched conversation lookups paginated via `next_token`. - **Billing-aware sidebar** — new sidebar footer (plan chip on cloud, community card when self-hosted), hoisted workspace settings, and an update-available indicator on the version badge. - **Longer sessions** — the default session lifetime is now seven days. - Engagement poll interval in settings is now labeled as a minimum floor. - The media editor's apply button is relabeled when the media is left unedited. ## Fixes - Repaired the Discord account reconnect button. - Bundled the generated emoji-picker data into the production image so the picker works when self-hosted. - The `prune-uploads` scheduled job now survives S3 listing errors instead of failing the run. **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.0-rc.5...v1.3.0-rc.6 --- ## v1.3.0-rc.5 — July 14, 2026 v1.3.0-rc.5 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.5 ## Features - Added Stripe promotion code support, tax ID collection, and automatic tax calculation for billing. **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.3.0-rc.4...v1.3.0-rc.5 --- ## v1.3.0-rc.4 — July 13, 2026 v1.3.0-rc.4 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.4 ## Fixes - Fixed form redirects to allow any HTTPS service. --- ## v1.3.0-rc.3 — July 13, 2026 v1.3.0-rc.3 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.3 fix cloud Stripe redirect **Full Changelog**: **https://github.com/coollabsio/shoutrrr/compare/v1.3.0-rc.2...v1.3.0-rc.3** --- ## v1.3.0-rc.2 — July 13, 2026 v1.3.0-rc.2 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.2 A feature-packed release: two new platforms (Meta & Discord), a public HTTP API, workspace subscriptions & usage metering, opt-in Sentry monitoring, and a full UI framework migration. > ### 🔁 Changes since `v1.3.0-rc.1` > - **feat:** opt-in Sentry error & performance monitoring (backend + browser) > - **fix(auth):** email-verification links no longer 403 when an email provider appends tracking params to the link > - **fix(auth):** the "Resend verification email" button works again (regressed in the Base UI migration) and now confirms with a toast ## ✨ Features ### New platforms - **meta:** Facebook, Instagram & Threads — publishing, metrics and engagement (#75) - **discord:** publish via channel webhooks (#84) ### Platform & API - **api:** HTTP API for programmatic posting (#74) - **billing:** workspace subscriptions with publish gates and X usage limits (#58) - **usage:** per-workspace platform-API usage metering (#63) - **settings:** enable/disable platforms instance-wide (#78) - **workspaces:** enable/disable connected accounts per workspace (#79) - **settings:** per-platform polling controls and instance usage reporting (8f618c0, 8c75f01) ### Observability - **sentry:** opt-in error & performance monitoring for the backend and browser — disabled unless a DSN is configured (a92dc55) ### Composer & X - **compose:** emoji browser — Frimousse picker + inline `:shortcode` typeahead (#73) - **compose:** Shift+Enter soft newline with platform-accurate blank-line preview (#72) - **compose:** accept more video formats via in-browser conversion (#88) - **x:** opt-in quote tweets from a pasted status link (#71) ### UI - **ui:** migrate from Radix to Base UI (#81) ## 🐛 Fixes - **auth:** keep email-verification links valid when an ESP appends click-tracking params to them (2173b31) - **auth:** fix the inert "Resend verification email" button and confirm the resend with a toast (2173b31) - **db:** make the schema and queries PostgreSQL-compatible (#85) - **compose:** resolve 422 on edited-video upload + allow media storage host in CSP (#70) - **bluesky:** block one-GIF/no-mix rule before posting (#69) - **compose:** restore clicks on the tab strip and wire up the "+N more" menu (8691c76) - **sidebar:** center collapsed icon rail (1d83e7f) - **engagement:** block replies from disabled accounts, avoid stamping failed reply fetches (08df0d3, 79f7970) ## 🔧 Self-hosting / Infra - **passport:** self-provision encryption keys (#87) - **deps:** bump the github-actions group (#77) and attest-build-provenance (#67) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.2.0...v1.3.0-rc.2 --- ## v1.3.0-rc.1 — July 13, 2026 v1.3.0-rc.1 (pre-release) · https://github.com/coollabsio/shoutrrr/releases/tag/v1.3.0-rc.1 A feature-packed release: two new platforms (Meta & Discord), a public HTTP API, workspace subscriptions & usage metering, and a full UI framework migration. ## ✨ Features ### New platforms - **meta:** Facebook, Instagram & Threads — publishing, metrics and engagement (#75) - **discord:** publish via channel webhooks (#84) ### Platform & API - **api:** HTTP API for programmatic posting (#74) - **billing:** workspace subscriptions with publish gates and X usage limits (#58) - **usage:** per-workspace platform-API usage metering (#63) - **settings:** enable/disable platforms instance-wide (#78) - **workspaces:** enable/disable connected accounts per workspace (#79) - **settings:** per-platform polling controls and instance usage reporting (8f618c0, 8c75f01) ### Composer & X - **compose:** emoji browser — Frimousse picker + inline `:shortcode` typeahead (#73) - **compose:** Shift+Enter soft newline with platform-accurate blank-line preview (#72) - **compose:** accept more video formats via in-browser conversion (#88) - **x:** opt-in quote tweets from a pasted status link (#71) ### UI - **ui:** migrate from Radix to Base UI (#81) ## 🐛 Fixes - **db:** make the schema and queries PostgreSQL-compatible (#85) - **compose:** resolve 422 on edited-video upload + allow media storage host in CSP (#70) - **bluesky:** block one-GIF/no-mix rule before posting (#69) - **compose:** restore clicks on the tab strip and wire up the "+N more" menu (8691c76) - **sidebar:** center collapsed icon rail (1d83e7f) - **engagement:** block replies from disabled accounts, avoid stamping failed reply fetches (08df0d3, 79f7970) ## 🔧 Self-hosting / Infra - **passport:** self-provision encryption keys (#87) - **deps:** bump the github-actions group (#77) and attest-build-provenance (#67) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.2.0...v1.3.0-rc.1 --- ## v1.2.0 — July 2, 2026 v1.2.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.2.0 A release centered on Bluesky OAuth support, composer workflow improvements, and MCP endpoint hardening. ## ✨ Features - **bluesky:** OAuth integration with enhancements and alt text support (#64) - **bluesky:** OAuth account connections (#62) - **bluesky:** custom instance selection (31ab09f) - **compose:** show timezone settings in the time picker (6a473ec) - **compose:** block publishing to disconnected accounts (6c0464c) - **compose:** keyboard shortcut for submitting posts (#60) - **mcp:** friendly browser landing page for the `/mcp` endpoint (1d19e57) ## 🐛 Fixes - **bluesky:** serialize OAuth token refresh to avoid a rotation race (6b9b036) - **bluesky:** validate OAuth service discovery URLs (4f0edbb) - **gif:** fix GIF publishing on X and Bluesky (#65) - **linkedin:** publish all text segments (deaf09b) - **composer:** improved highlight regex and tests (#57) - **mcp:** never serve the landing page to SSE/GET protocol clients (9dedb3e) - **accounts:** normalize Bluesky handles with `@` prefix (#59) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.1.0...v1.2.0 ## 🎉 New Contributors - @scanash00 made their first contribution in #64 - @laborin made their first contribution in #65 --- ## v1.1.0 — June 30, 2026 v1.1.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.1.0 A release focused on self-hosting hardening, security patches, and composer/settings improvements. ## ✨ Features - **compose:** link URLs in post previews (c8f94b1) - **compose:** improved mention picker (#47) - **settings:** profile and workspace photo uploads (437b6b6) ## 🐛 Fixes - **notifications:** correct unread notification position (#56) - **cmd+k:** fix global search filtering (#48) - **cache:** prevent stale Inertia page state (bfedb37) ## 🚀 Self-hosting / Deployment - pass env file through compose files for missing configurations (#55) - trust reverse-proxy headers via `TRUSTED_PROXIES` (#53) - handle TLS mixed-content issues behind proxies (#54) - default `QUEUE_WORKER_COUNT` to 1 so supervisord starts (#52) ## 🔒 Security / CI - update Guzzle to patch security advisories (0b57b8f) - add supply-chain security scanning to CI (682a707) **Full Changelog**: https://github.com/coollabsio/shoutrrr/compare/v1.0.0...v1.1.0 ## 🎉 New Contributors - @raulpopadineti made their first contribution in #47 - @CyrisXD made their first contribution in #52 --- ## v1.0.0 — June 29, 2026 v1.0.0 · https://github.com/coollabsio/shoutrrr/releases/tag/v1.0.0 init 🌮 release