posthive
Allows scheduling and publishing posts to Bluesky, including text, images, and first comment support.
Allows scheduling and publishing messages to Discord channels.
Allows scheduling and publishing posts to Facebook, including text and images.
Allows scheduling and publishing Instagram posts, reels, stories, and carousels (up to 10 items) with image alt text.
Allows scheduling and publishing posts to Mastodon instances.
Allows scheduling and publishing Pinterest Pins with dedicated Title and Description fields (image required).
Allows scheduling and publishing messages to Telegram channels or groups.
Allows scheduling and publishing posts to Threads, including text and images.
Allows scheduling and publishing posts to Tumblr.
Allows scheduling and publishing YouTube videos (short and long-form) with dedicated Title/Description fields.
Allows scheduling and publishing YouTube Shorts with dedicated Title/Description fields.
Features
Scheduling
Multi-platform posting - write once, publish to multiple platforms simultaneously
Bulk CSV scheduling - upload a spreadsheet to schedule hundreds of posts; per-row platform exclusions (
!instagram)Post templates - save, load, and delete reusable post drafts
Dry run mode - full pipeline test without making real API calls
First comment scheduling - auto-reply immediately after the main post goes live
Per-platform overrides - custom text and first comment per account (Pro+)
AI & Agents
MCP server - connect Claude, ChatGPT, Cursor, VS Code, Claude Code, Codex, OpenClaw, Hermes Agent, or any MCP-compatible agent via one bare URL
OAuth 2.0 + PKCE - full dynamic client registration flow; no API key to paste for any client — the agent opens your browser to sign in
posthive-cli- shell CLI (npx posthive-cli) withlogin/logout/whoami, mirrors the full public API, ships a bundledSKILL.mdfor agent self-discoveryposthive-mcp- standalone MCP server package (npx posthive-mcp); shares the same login asposthive-clivia~/.posthive/config.json10 MCP tools - list accounts, create/get/update/delete posts, approve drafts, duplicate, list/use templates
Media type support - Instagram media type (post/reel/story) and YouTube type (short/video) via MCP
Draft-first - every agent-created post lands as a draft for human review unless scheduling is explicitly requested
Plan-gated - MCP/API access requires Pro or Team plan (self-hosted with billing disabled: unlimited)
Media
Images (up to 4 per post; plan-gated), video (up to 100 MB)
Instagram Reels, Stories, and carousel (up to 10 items)
YouTube Shorts + long-form video with dedicated Title/Description fields
Pinterest Pins with dedicated Title/Description fields image required
Alt text on every image
Clipboard paste and drag-and-drop upload
Calendar & Posts
FullCalendar month/week/day views with drag-to-reschedule
Real-time job status via Server-Sent Events
Platform filter in list and calendar views
Retry failed platforms (re-queues only failed targets; skips already-successful ones)
Inline edit and reschedule from list view
Auth & Accounts
Email + password auth (JWT, bcrypt, silent refresh)
Email verification and password reset via Resend
API keys for programmatic access (Pro/Team plans)
Token expiry warnings with one-click reconnect
Background token auto-refresh (Threads, Instagram, Facebook, YouTube every 12h)
Infrastructure
BullMQ queue backed by Redis (Upstash or Railway)
AES-256-GCM encryption for all stored OAuth credentials
Sentry error monitoring
Orphan upload cleanup cron (every 6h)
Rate limiting per route
CSRF nonce on all OAuth flows
Billing (optional)
Dodo Payments - Creator, Pro, Team plans
14-day free trial; INR/USD currency detection
Set
ENABLE_BILLING=falsefor self-hosted mode all features unlocked, no plan limits
Related MCP server: postfast-mcp
Tech Stack
Layer | Technology |
Frontend | Next.js 16 (App Router), React 18, Tailwind CSS |
Backend | Fastify v4, TypeScript ESM, Node.js |
Database | Prisma 5 - Postgres (dev via Docker or local install) / Postgres (prod) |
Queue | BullMQ 5 + Redis (Upstash or Railway) |
Resend | |
Storage | Local disk (dev) / Supabase Storage (prod) |
Billing | Dodo Payments |
Monitoring | Sentry |
Calendar | FullCalendar 6 |
Project Structure
posthive/
├── apps/
│ ├── api/ # Fastify v4 API (Node.js, TypeScript, ESM)
│ │ ├── prisma/ # Schema + migrations
│ │ └── src/
│ │ ├── adapters/ # Platform adapters (Bluesky, Threads, Instagram, LinkedIn, Mastodon, YouTube, Facebook, Pinterest, X/Twitter, Telegram, Nostr, Discord, Tumblr, Lemmy)
│ │ ├── lib/ # Auth, queue, worker, encryption, storage, mailer, plans
│ │ └── routes/ # auth, accounts, jobs, templates, upload, billing, user, apiKeys, publicApi, mcp, oauth
│ ├── web/ # Next.js 16 frontend
│ │ └── src/
│ │ ├── app/ # Pages: compose, jobs, accounts, billing, settings, docs, agent, features, platforms
│ │ └── components/ # Sidebar, CalendarView, BulkScheduleModal, Toast, PlatformPreview, AgentSetupTabs, etc.
│ ├── cli/ # posthive-cli — npm-published shell CLI (login/logout/whoami + full API)
│ └── mcp/ # posthive-mcp — npm-published standalone MCP server
└── package.json # pnpm workspace rootSelf-hosting
The fastest path is Docker — no Node.js or pnpm needed on the host. You get two containers (API + Web) backed by Postgres and Redis, all wired up in one docker compose command.
Prerequisites
Docker Engine 24+ with the Compose v2 plugin (
docker compose, notdocker-compose)
1. Clone and configure
git clone https://github.com/AstaBlackClove/posthive.git
cd posthive
cp apps/api/.env.example .envOpen .env and set at minimum:
# ── Postgres ────────────────────────────────────────────
POSTGRES_PASSWORD=change_me_to_a_strong_password
# ── Secrets (generate each with the command below) ──────
ENCRYPTION_KEY=<64-char hex> # NEVER change after accounts are saved
JWT_ACCESS_SECRET=<64-char hex>
JWT_REFRESH_SECRET=<64-char hex>
# ── URLs ────────────────────────────────────────────────
WEB_URL=http://localhost:3000 # public URL of the web app
PUBLIC_API_URL=http://localhost:3001 # public URL of the API (must be reachable from the internet for Meta/Instagram/Threads image fetches)Generate secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
ENCRYPTION_KEYencrypts all stored OAuth tokens. Write it down — changing it after accounts are saved makes all connected accounts permanently unusable.
2. Start
docker compose up -d --buildThe first build takes 2–5 minutes. Once done, Posthive is running:
Service | URL |
Web | |
API |
Register your account at /register. Billing is disabled by default — all features are unlocked.
3. Custom domain with a reverse proxy
Set the public URLs in .env before building, then point your reverse proxy at the containers.
Caddy (recommended — auto HTTPS)
yourdomain.com {
reverse_proxy localhost:3000
}
api.yourdomain.com {
reverse_proxy localhost:3001
}Set in .env:
WEB_URL=https://yourdomain.com
PUBLIC_API_URL=https://api.yourdomain.comThen rebuild:
docker compose up -d --buildnginx
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}4. Persistent uploads
By default, uploaded images are stored inside the container and lost on rebuild. To persist them, add a volume to docker-compose.yml:
api:
...
volumes:
- uploads:/app/apps/api/uploads
volumes:
postgres_data:
redis_data:
uploads: # ← add thisFor production, use Supabase Storage instead — set STORAGE_PROVIDER=supabase and the SUPABASE_* vars.
5. Updating
git pull
docker compose up -d --buildMigrations run automatically on API startup.
Prerequisites (developer setup)
Node.js >= 20
pnpm >= 9 -
npm install -g pnpmRedis - Upstash free tier or Railway Redis
Postgres - Docker Desktop (recommended, zero config
pnpm dev:dbpullspostgres:15automatically on first run) or a local Postgres install
Getting Started
1. Clone and install
git clone https://github.com/AstaBlackClove/posthive.git
cd posthive
pnpm install2. Configure environment
cp apps/api/.env.example apps/api/.envFill in the values see Environment Variables below.
3. Database
Option A - Docker (recommended, no Postgres install needed)
# Start a Postgres container (creates it on first run, starts it on subsequent runs)
pnpm dev:dbUse this DATABASE_URL in apps/api/.env:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"The container is named posthive-pg. Stop it with pnpm db:stop, restart with pnpm db:start.
Option B - SQLite (no Docker, quickest setup)
Change the provider in apps/api/prisma/schema.prisma:
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}Use this DATABASE_URL in apps/api/.env:
DATABASE_URL="file:./dev.db"SQLite is fine for local development and self-hosting on a single server. Use Postgres in production for reliability and concurrent writes.
4. Run migrations
cd apps/api
pnpm db:migrate5. Run dev servers
# from project root starts Docker Postgres + API + Web in parallel
pnpm devIf you chose SQLite (Option B), skip
pnpm dev:dbjust runpnpm dev:apiandpnpm dev:webseparately, or usepnpm devafter commenting out thedev:dbstep.
Service | URL |
Web | |
API | |
Prisma Studio |
|
Environment Variables
apps/api/.env
Core
Variable | Required | Description |
| No | API port. Defaults to |
| Yes |
|
| Yes | 64-char hex. AES-256-GCM key for credentials. Never change after data is written |
| Yes | Upstash or Railway Redis URL |
| Yes | Frontend origin for CORS + OAuth redirects. |
| Prod | Set to |
| Prod | Set to |
Auth
Variable | Required | Description |
| No |
|
| local auth | 64-char hex |
| local auth | 64-char hex |
| Supabase |
|
| Supabase | Supabase anon key |
| Supabase | Supabase service role key |
Variable | Required | Description |
| No | Resend API key. Falls back to console in dev |
| No | Verified sender address. e.g. |
Storage
Variable | Required | Description |
| No |
|
| Supabase | Bucket name. Defaults to |
| Public HTTPS URL of the API Meta fetches images from here |
OAuth - Threads
Variable | Description |
| Meta app ID |
| Meta app secret |
| Must be public HTTPS |
OAuth - Instagram
Variable | Description |
| Meta app ID |
| Meta app secret |
| Must be public HTTPS |
OAuth - LinkedIn
Variable | Description |
| LinkedIn app client ID |
| LinkedIn app client secret |
| Must be public HTTPS |
OAuth - Mastodon
Variable | Description |
| Client key from Mastodon app settings |
| Client secret from Mastodon app settings |
| Must be public HTTPS |
OAuth - YouTube
Variable | Description |
| Google OAuth client ID |
| Google OAuth client secret |
| Use |
OAuth - Facebook Pages
Variable | Description |
| Meta app ID |
| Meta app secret |
| Must be public HTTPS |
OAuth - Pinterest
Variable | Description |
| Pinterest App ID from developers.pinterest.com |
| Pinterest App secret key |
| Must be public HTTPS |
| Set |
| Manually-generated sandbox token (My Apps → Generate Access Token → Sandbox). Only used when |
Pinterest requires Standard access approval for production pin creation. Apply at developers.pinterest.com → My Apps → Request upgraded access. Until approved, set
PINTEREST_SANDBOX=trueand use a sandbox token.
OAuth - X (Twitter)
Variable | Description |
| API Key (Consumer Key) from developer.x.com |
| API Key Secret (Consumer Secret) |
| Must be public HTTPS — OAuth 1.0a callback URL |
Uses OAuth 1.0a (not 2.0). Requires Pro or Team plan when billing is enabled.
OAuth - Discord
Variable | Description |
| OAuth2 Client ID from discord.com/developers |
| OAuth2 Client Secret |
| Bot token (Bot tab in your Discord app) |
| Must be public HTTPS — OAuth 2.0 callback URL |
OAuth - Tumblr
Variable | Description |
| Consumer Key from tumblr.com/oauth/apps |
| Consumer Secret |
| Must match the Default callback URL registered in your Tumblr app exactly |
Tumblr uses OAuth 1.0a. Only one callback URL can be registered — use your production URL.
Billing
Variable | Required | Description |
| No | Set to |
| Billing |
|
| Billing | Dodo API key |
| Billing |
|
| Billing | Dodo product ID for Creator plan |
| Billing | Dodo product ID for Pro plan |
| Billing | Dodo product ID for Team plan |
Monitoring
Variable | Required | Description |
| No | Sentry DSN. Omit to disable |
Generate secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"apps/web/.env.local
Variable | Required | Description |
| Yes | API URL from the browser. |
| Yes | Public URL of the web app. Used for OG images, sitemap, robots.txt. |
| No | Must match |
Connecting Platforms
Bluesky
Go to Accounts in the app
Enter your handle (e.g.
you.bsky.social)Generate an app password at bsky.app → Settings → App Passwords
Enter it and click Connect no OAuth needed
Threads
Create an app at developers.facebook.com and add the Threads use case
Set the OAuth redirect URI to
https://your-domain/auth/threads/callbackAdd
THREADS_APP_IDandTHREADS_APP_SECRETto.env
In development mode only Threads Testers can connect. Submit for Meta App Review (
threads_basic+threads_content_publish) for public access.
Add the Instagram product to your Meta app
Set the OAuth redirect URI to
https://your-domain/auth/instagram/callbackRequires a Professional (Business or Creator) Instagram account
Create an app at developer.linkedin.com
Add the Share on LinkedIn and Sign In with LinkedIn using OpenID Connect products
Set redirect URI to
https://your-domain/auth/linkedin/callback
Mastodon
Log in to your Mastodon instance → Settings → Development → New Application
Scopes:
read:accounts,write:statuses,write:mediaSet redirect URI to
https://your-domain/auth/mastodon/callback
Works with any Mastodon-compatible instance mastodon.social, fosstodon.org, hachyderm.io, etc.
YouTube
Create a project in Google Cloud Console
Enable the YouTube Data API v3
Create OAuth 2.0 credentials; set redirect URI to
http://localhost:3001/auth/youtube/callback
Google requires app verification for production. Until verified, refresh tokens expire after 7 days.
Facebook Pages
Use the same Meta app as Threads/Instagram
Add Manage everything on your Page use case
Set redirect URI to
https://your-domain/auth/facebook/callbackRequires a Facebook Page personal profiles are not supported by the Graph API
First comment support requires
pages_manage_engagement(pending Meta app review).
Create an app at developers.pinterest.com
Enable scopes:
boards:read,pins:read,pins:write,user_accounts:readSet redirect URI to
https://your-domain/auth/pinterest/callbackSet
PINTEREST_CLIENT_IDandPINTEREST_CLIENT_SECRETin.env
Trial access (default): New apps get Trial access pins can only be created in the sandbox.
Set
PINTEREST_SANDBOX=trueGenerate a sandbox token: My Apps → Manage → Generate Access Token → Sandbox
Set
PINTEREST_SANDBOX_TOKENto that token
Standard access (production): Apply at developers.pinterest.com → My Apps → Request upgraded access. Once approved, set PINTEREST_SANDBOX=false and remove PINTEREST_SANDBOX_TOKEN. Users connect via normal OAuth.
Posts as Pins on the user's first board. Image is required posts without an image are blocked at the UI level.
X (Twitter)
Create a project + app at developer.x.com
Set App permissions to Read and write
Enable OAuth 1.0a and set the callback URL to
https://your-domain/auth/twitter/callbackCopy the API Key and API Key Secret into
X_API_KEY/X_API_SECRET
Requires Pro or Team plan when billing is enabled. Uses OAuth 1.0a, not OAuth 2.0.
Telegram
No OAuth needed — uses the Telegram Bot API directly.
Open Telegram and message @BotFather →
/newbot→ follow the prompts to get a bot tokenCreate a Telegram channel (public or private)
Add your bot to the channel as an Administrator with at least the Post Messages permission
Go to Accounts in Posthive → Connect Telegram Channel
Paste the bot token and your channel username (e.g.
@mychannel) or numeric chat ID (e.g.-1001234567890)
Private channels: use the numeric chat ID. Forward any message from the channel to @userinfobot to get it. One bot can serve multiple channels — connect each channel separately in Posthive. No environment variables needed. Credentials are stored encrypted per-user.
Nostr
No OAuth, no app registration — uses your keypair directly.
Go to Accounts in Posthive → Connect Nostr
Paste your
nsec1...private key — or click Generate a new keypair to create a fresh oneYour profile name and photo are fetched automatically from relays
Your
nsecis stored AES-256-GCM encrypted and never exposed. Posts publish as Kind 1 notes to four default relays (Damus, Nostr.band, nos.lol, Snort). Images are appended as URLs in the note content and tagged with NIP-92 imeta for clients that support inline rendering. No environment variables needed.
Discord
OAuth + Bot API. Posts are sent via a webhook auto-created at channel connect time.
Go to discord.com/developers → New Application → name it Posthive
Go to Bot tab → Add Bot → copy the bot token
Go to OAuth2 → General → copy Client ID and Client Secret → add redirect URI
Add to
.env:
DISCORD_CLIENT_ID="your-client-id"
DISCORD_CLIENT_SECRET="your-client-secret"
DISCORD_BOT_TOKEN="your-bot-token"
DISCORD_REDIRECT_URI="https://your-domain.com/auth/discord/callback"Go to Accounts in Posthive → Connect Discord → authorise on Discord → pick a channel
Posthive auto-creates a webhook for the selected channel so messages appear under the Posthive name. Discord shows an APP label on all programmatic posts — this is a Discord platform requirement.
Tumblr
OAuth 1.0a (HMAC-SHA1). Tokens never expire — connect once and it works indefinitely.
Go to tumblr.com/oauth/apps → Register application (instant, no review)
Set Default callback URL to
https://your-domain.com/auth/tumblr/callbackAdd to
.env:
TUMBLR_CONSUMER_KEY="your-consumer-key"
TUMBLR_CONSUMER_SECRET="your-consumer-secret"
TUMBLR_REDIRECT_URI="https://your-domain.com/auth/tumblr/callback"Go to Accounts in Posthive → Connect Tumblr → approve the OAuth prompt
Posts to your primary Tumblr blog using NPF (Neue Post Format). Text and images supported. Tumblr app registration requires no business verification or API review.
Lemmy
Username + password auth. No OAuth, no app registration, no API approval — works with any Lemmy instance.
Create a Lemmy account on any instance (e.g. lemmy.world, lemmy.ml, beehaw.org)
Go to Accounts in Posthive → Connect Lemmy
Enter your instance URL, username, password, and the community to post to (e.g.
selfhosted@lemmy.world)
No environment variables needed. Credentials are stored AES-256-GCM encrypted. The first line of your post becomes the Lemmy post title; the rest becomes the body. Images are uploaded via pictrs.
Bulk CSV Scheduling
Upload a CSV to schedule multiple posts at once. Available from the Posts page (Bulk button) and the Compose page (Bulk CSV button).
CSV format:
scheduled_for,text,accounts,comment,image_urls
2026-08-01 09:00,Good morning 🌅,all,,
2026-08-02 14:30,Blog post link,bluesky|mastodon,Link in first comment,
2026-08-03 18:00,Skip Instagram today,!instagram,,
2026-08-04 10:00,With an image,linkedin,,https://example.com/image.jpg
2026-08-05 12:00,Two images,bluesky|threads,,https://img1.jpg;https://img2.jpgAccounts column syntax:
all- all connected accounts except YouTubebluesky|mastodon- specific platforms, pipe-separated!instagram- all platforms except Instagram (and YouTube)all|!instagram|!linkedin- all except Instagram and LinkedIn
YouTube is not supported in bulk scheduling it requires a video file. Use Compose instead. Instagram rows must include at least one image URL.
How Scheduling Works
Write a post in Compose, pick accounts, set a time
API creates a
PostJobin the DB and enqueues a BullMQ delayed jobAt the scheduled time BullMQ fires the job (~1 second accuracy)
The worker processes each platform independently:
Refreshes OAuth tokens if needed
Posts the main content
Posts the first comment as a reply (if provided)
Each step is persisted before the next crash-safe and resumable
Real-time status updates via Server-Sent Events on the Posts page
Job state machine (per PostJobTarget)
pending → running → post_done → comment_done (= done)
↘ post_failed
↘ comment_failedPost Templates
Save and reuse post drafts from the Compose page:
Write a post and click + Save in the POST section header
Give it a name (must be unique)
Click Templates to open the dropdown and load any saved template
Hover a template and click ✕ to delete it
Templates save: post text, first comment, YouTube title/description/type, and Pinterest title/description.
API Reference
Posthive includes a full public REST API for Pro and Team plans (or all users when billing is disabled).
Base URL: https://your-api-domain/api/v1
Authentication: Bearer token — create an API key in Settings.
Authorization: Bearer ph_your_api_keyEndpoints:
Method | Path | Description |
GET | /me | Identify the authenticated user (used by CLI/MCP login) |
GET | /accounts | List connected accounts |
POST | /posts | Schedule a post |
GET | /posts | List posts (cursor-paginated) |
GET | /posts/:id | Get single post |
PATCH | /posts/:id | Update/reschedule pending post |
POST | /posts/:id/approve | Promote a draft to scheduled |
POST | /posts/:id/duplicate | Clone a post as a new draft |
DELETE | /posts/:id | Delete post |
POST | /upload | Upload media file |
GET | /templates | List templates |
POST | /templates | Create template |
See the full documentation for request/response schemas.
MCP — AI Agent Integration
Posthive exposes an MCP (Model Context Protocol) server so AI agents can schedule and manage posts directly. Every client below connects with the same bare URL — no API key to generate, copy, or paste. See posthive.co/agent for a full interactive walkthrough per client.
Requires: Pro or Team plan (self-hosted with billing disabled: unlimited) · Rate limit: 60 req/min
Claude / ChatGPT (OAuth connector, no install)
Claude: Settings → Connectors → Add custom connector. ChatGPT: Settings → Apps → Advanced settings → enable Developer mode, then Settings → Apps → Add app.
Enter
https://your-api/mcpApprove access in the browser prompt that opens
Claude Code
claude mcp add --transport http posthive https://your-api/mcpThe first tool call opens your browser to sign in.
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"posthive": { "url": "https://your-api/mcp" }
}
}VS Code (GitHub Copilot Chat)
Add to .vscode/mcp.json:
{
"servers": {
"posthive": { "type": "http", "url": "https://your-api/mcp" }
}
}Codex
Add to ~/.codex/config.toml:
[mcp_servers.posthive]
url = "https://your-api/mcp"OpenClaw
openclaw mcp set posthive '{"url":"https://your-api/mcp","transport":"streamable-http"}'Hermes Agent
Add to ~/.hermes/config.yaml:
mcp_servers:
posthive:
url: "https://your-api/mcp"CLI for shell agents (OpenClaw, custom pipelines, scripts)
Not every agent speaks MCP. posthive-cli is a thin shell wrapper over the same public API:
npx posthive-cli login # opens your browser, no API key needed
npx posthive-cli accounts:list
npx posthive-cli posts:create --content "Hello" --accounts acc_1,acc_2Every command outputs structured JSON and ships a bundled SKILL.md for agent self-discovery. posthive-mcp (the npm-published MCP server) shares the same login via ~/.posthive/config.json — sign in once, use both.
Fallback: API key in URL
For a client that doesn't support OAuth discovery, embed the key directly instead of the bare URL above: https://your-api/mcp/ph_your_api_key_here. Keep this URL private — revoke and regenerate from Settings → API Keys if it leaks.
Available Tools
Tool | Description |
| List all connected social accounts |
| Create a scheduled or draft post |
| Get a single post by ID |
| List posts with optional status filter |
| Promote a draft to scheduled |
| Update content or reschedule a pending post |
| Clone a post as a new draft |
| Delete a post |
| List saved post templates |
| Create a post from a template |
Media via MCP
MCP tools accept media_urls (array of public URLs). Binary upload is not possible via MCP — upload files first via POST /api/v1/upload and pass the returned URLs to create_post.
Instagram media_type: post · reel · story
YouTube youtube_type: short · video
Plans
Plan | Accounts | Posts/month | API Keys |
Creator | 3 | 400 | - |
Pro | 15 | Unlimited | Unlimited |
Team | 50 | Unlimited | Unlimited |
All plans include a 14-day free trial. Powered by Dodo Payments.
Set ENABLE_BILLING=false for self-hosted mode all features unlocked, no plan limits, no Dodo account needed.
Character Limits
Platform | Limit |
Bluesky | 300 graphemes |
Threads | 500 characters |
2,200 characters | |
3,000 characters | |
Mastodon | 500 characters |
YouTube | Title: 100 · Description: 5,000 |
Facebook Pages | 63,206 characters |
Title: 100 · Description: 500 | |
X (Twitter) | 280 characters |
Telegram | 4,096 characters |
Nostr | 10,000 characters |
Discord | 2,000 characters |
Tumblr | 4,096 characters |
Lemmy | 10,000 characters |
Self-Hosting
Posthive is designed to be self-hosted. Billing is optional.
Without billing (default):
# apps/api/.env
ENABLE_BILLING=false
# apps/web/.env.local
NEXT_PUBLIC_ENABLE_BILLING=falseAll features are unlocked for all users. No Dodo account needed. Onboarding skips plan selection.
With billing:
ENABLE_BILLING=true
NEXT_PUBLIC_ENABLE_BILLING=trueCreate a Dodo Payments account and fill in all DODO_* env vars. Users get a 14-day free trial on signup.
Production Deployment
Recommended stack: Railway (API + Redis) · Supabase (Postgres + Storage) · Vercel (Next.js)
1. Supabase
Create a project at supabase.com
Storage → create a bucket named
media→ set it to PublicSettings → Database → Connection String → Session pooler (port 5432) → copy URI
2. Railway - API
New project → Deploy from GitHub → Root Directory: leave blank (repo root)
Add a Redis service → copy private URL as
${{ Redis.REDIS_URL }}Set environment variables (see table above)
Builder: Railpack (default — do not switch to Dockerfile)
Build Command:
pnpm install --frozen-lockfile --filter api... && pnpm --filter api exec prisma generate && pnpm --filter api buildStart Command:
cd apps/api && npx prisma migrate deploy && node dist/index.jsAdd custom domain → set port to
3001
3. Vercel - Frontend
Import same repo → Root Directory:
apps/webAdd env vars:
NEXT_PUBLIC_API_URLandNEXT_PUBLIC_ENABLE_BILLING
4. Migrations
Migrations run automatically on deploy via prisma migrate deploy. To create a migration locally:
cd apps/api
npx prisma migrate dev --name describe_your_change
git add prisma/migrations
git commit -m "db: add <describe_your_change> migration"Use the direct connection URL (not the pooler) when running
prisma migrate devlocally.
Adding a New Platform
Create
apps/api/src/adapters/<platform>.tsimplementingPlatformAdapterRegister in
apps/api/src/adapters/index.tsAdd OAuth routes in
apps/api/src/routes/auth.tsAdd platform card in
apps/web/src/app/accounts/page.tsx— also add toPLATFORM_METAandRECONNECT_URLSAdd favicon domain in
apps/web/src/components/PlatformIcon.tsxAdd
PLATFORM_COLORandPLATFORM_LIMITinapps/web/src/components/PlatformPreview.tsxAdd preview component in
apps/web/src/components/PlatformPreview.tsxAdd to
PLATFORMS_GRIDinapps/web/src/app/page.tsx(landing page grid + hero card)Add to
PLATFORMS_NAVinapps/web/src/components/LandingNav.tsxAdd platform data object in
apps/web/src/app/platforms/[platform]/page.tsxAdd docs section in
apps/web/src/app/docs/page.tsxAdd to
NO_COMMENT_PLATFORMSin compose, EditPostDialog, andjobRunner.tsif the platform has no comment APIAdd env vars to
apps/api/.env.exampleand document in this README
Community
Join the Posthive Discord for support, feature requests, and to connect with other users:
License
GNU Affero General Public License v3.0 see LICENSE for details.
If you modify this project and run it as a network service, you must make your modified source code available to users of that service.
This server cannot be installed
Maintenance
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AstaBlackClove/posthive'
If you have feedback or need assistance with the MCP directory API, please join our Discord server