Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Posthive

FreeNot checked

Schedule and manage social media posts across 13 platforms (Bluesky, Threads, Instagram, LinkedIn, Mastodon, YouTube, Facebook, Pinterest, Telegram, Nostr, X/Tw

GitHubEmbed

About

Schedule and manage social media posts across 13 platforms (Bluesky, Threads, Instagram, LinkedIn, Mastodon, YouTube, Facebook, Pinterest, Telegram, Nostr, X/Twitter, Discord, Tumblr and more). OAuth 2.0 + PKCE, 10 tools, draft-first workflow for AI agents.

README

Posthive

Posthive

The agentic social media scheduling platform. Plan, create, and publish posts across every major social network with built-in MCP support for Claude, Cursor, ChatGPT and AI agents.
Self-hostable · Open-source · AGPL-3.0

License: AGPL-3.0 GitHub Repo Discord

Posthive cover

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) with login/logout/whoami, mirrors the full public API, ships a bundled SKILL.md for agent self-discovery
  • posthive-mcp - standalone MCP server package (npx posthive-mcp); shares the same login as posthive-cli via ~/.posthive/config.json
  • 10 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=false for self-hosted mode all features unlocked, no plan limits

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)
Email 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 root

Self-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

1. Clone and configure

git clone https://github.com/AstaBlackClove/posthive.git
cd posthive
cp apps/api/.env.example .env

Open .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_KEY encrypts 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 --build

The first build takes 2–5 minutes. Once done, Posthive is running:

Service URL
Web http://localhost:3000
API http://localhost:3001

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

Then rebuild:

docker compose up -d --build

nginx

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 this

For production, use Supabase Storage instead — set STORAGE_PROVIDER=supabase and the SUPABASE_* vars.

5. Updating

git pull
docker compose up -d --build

Migrations run automatically on API startup.


Prerequisites (developer setup)

  • Node.js >= 20
  • pnpm >= 9 - npm install -g pnpm
  • Redis - Upstash free tier or Railway Redis
  • Postgres - Docker Desktop (recommended, zero config pnpm dev:db pulls postgres:15 automatically 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 install

2. Configure environment

cp apps/api/.env.example apps/api/.env

Fill 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:db

Use 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:migrate

5. Run dev servers

# from project root starts Docker Postgres + API + Web in parallel
pnpm dev

If you chose SQLite (Option B), skip pnpm dev:db just run pnpm dev:api and pnpm dev:web separately, or use pnpm dev after commenting out the dev:db step.

Service URL
Web http://localhost:3000
API http://localhost:3001
Prisma Studio pnpm db:studiohttp://localhost:5555

Environment Variables

apps/api/.env

Core

Variable Required Description
PORT No API port. Defaults to 3001
DATABASE_URL Yes postgresql://postgres:postgres@localhost:5432/postgres (Docker dev) or file:./dev.db (SQLite dev) or Postgres URL in prod
ENCRYPTION_KEY Yes 64-char hex. AES-256-GCM key for credentials. Never change after data is written
REDIS_URL Yes Upstash or Railway Redis URL
WEB_URL Yes Frontend origin for CORS + OAuth redirects. http://localhost:3000 in dev
NODE_ENV Prod Set to production
SECURE_COOKIES Prod Set to true to require HTTPS for auth cookies

Auth

Variable Required Description
AUTH_PROVIDER No local (default) or supabase
JWT_ACCESS_SECRET local auth 64-char hex
JWT_REFRESH_SECRET local auth 64-char hex
SUPABASE_URL Supabase https://your-project.supabase.co
SUPABASE_ANON_KEY Supabase Supabase anon key
SUPABASE_SERVICE_ROLE_KEY Supabase Supabase service role key

Email

Variable Required Description
RESEND_API_KEY No Resend API key. Falls back to console in dev
EMAIL_FROM No Verified sender address. e.g. Posthive <[email protected]>

Storage

Variable Required Description
STORAGE_PROVIDER No supabase for prod; unset = local disk
SUPABASE_STORAGE_BUCKET Supabase Bucket name. Defaults to media
PUBLIC_API_URL Instagram Public HTTPS URL of the API Meta fetches images from here

OAuth - Threads

Variable Description
THREADS_APP_ID Meta app ID
THREADS_APP_SECRET Meta app secret
THREADS_REDIRECT_URI Must be public HTTPS

OAuth - Instagram

Variable Description
INSTAGRAM_APP_ID Meta app ID
INSTAGRAM_APP_SECRET Meta app secret
INSTAGRAM_REDIRECT_URI Must be public HTTPS

OAuth - LinkedIn

Variable Description
LINKEDIN_CLIENT_ID LinkedIn app client ID
LINKEDIN_CLIENT_SECRET LinkedIn app client secret
LINKEDIN_REDIRECT_URI Must be public HTTPS

OAuth - Mastodon

Variable Description
MASTODON_CLIENT_ID Client key from Mastodon app settings
MASTODON_CLIENT_SECRET Client secret from Mastodon app settings
MASTODON_REDIRECT_URI Must be public HTTPS

OAuth - YouTube

Variable Description
YOUTUBE_CLIENT_ID Google OAuth client ID
YOUTUBE_CLIENT_SECRET Google OAuth client secret
YOUTUBE_REDIRECT_URI Use http://localhost:3001/auth/youtube/callback Google rejects tunnel domains; localhost is exempt

OAuth - Facebook Pages

Variable Description
FACEBOOK_APP_ID Meta app ID
FACEBOOK_APP_SECRET Meta app secret
FACEBOOK_REDIRECT_URI Must be public HTTPS

OAuth - Pinterest

Variable Description
PINTEREST_CLIENT_ID Pinterest App ID from developers.pinterest.com
PINTEREST_CLIENT_SECRET Pinterest App secret key
PINTEREST_REDIRECT_URI Must be public HTTPS
PINTEREST_SANDBOX Set true while app has Trial access routes API calls to the sandbox
PINTEREST_SANDBOX_TOKEN Manually-generated sandbox token (My Apps → Generate Access Token → Sandbox). Only used when PINTEREST_SANDBOX=true

Pinterest requires Standard access approval for production pin creation. Apply at developers.pinterest.com → My Apps → Request upgraded access. Until approved, set PINTEREST_SANDBOX=true and use a sandbox token.

OAuth - X (Twitter)

Variable Description
X_API_KEY API Key (Consumer Key) from developer.x.com
X_API_SECRET API Key Secret (Consumer Secret)
X_CALLBACK_URL 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
DISCORD_CLIENT_ID OAuth2 Client ID from discord.com/developers
DISCORD_CLIENT_SECRET OAuth2 Client Secret
DISCORD_BOT_TOKEN Bot token (Bot tab in your Discord app)
DISCORD_REDIRECT_URI Must be public HTTPS — OAuth 2.0 callback URL

OAuth - Tumblr

Variable Description
TUMBLR_CONSUMER_KEY Consumer Key from tumblr.com/oauth/apps
TUMBLR_CONSUMER_SECRET Consumer Secret
TUMBLR_REDIRECT_URI 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
ENABLE_BILLING No Set to true to enable Dodo Payments and plan limits
DODO_ENV Billing test_mode or live_mode
DODO_API_KEY Billing Dodo API key
DODO_WEBHOOK_SECRET Billing whsec_... webhook signing secret
DODO_PRODUCT_CREATOR Billing Dodo product ID for Creator plan
DODO_PRODUCT_PRO Billing Dodo product ID for Pro plan
DODO_PRODUCT_TEAM Billing Dodo product ID for Team plan

Monitoring

Variable Required Description
SENTRY_DSN 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
NEXT_PUBLIC_API_URL Yes API URL from the browser. http://localhost:3001 in dev
NEXT_PUBLIC_WEB_URL Yes Public URL of the web app. Used for OG images, sitemap, robots.txt. http://localhost:3000 in dev, https://yourdomain.com in prod
NEXT_PUBLIC_ENABLE_BILLING No Must match ENABLE_BILLING in the API

Connecting Platforms

Bluesky

  1. Go to Accounts in the app
  2. Enter your handle (e.g. you.bsky.social)
  3. Generate an app password at bsky.app → Settings → App Passwords
  4. Enter it and click Connect no OAuth needed

Threads

  1. Create an app at developers.facebook.com and add the Threads use case
  2. Set the OAuth redirect URI to https://your-domain/auth/threads/callback
  3. Add THREADS_APP_ID and THREADS_APP_SECRET to .env

In development mode only Threads Testers can connect. Submit for Meta App Review (threads_basic + threads_content_publish) for public access.

Instagram

  1. Add the Instagram product to your Meta app
  2. Set the OAuth redirect URI to https://your-domain/auth/instagram/callback
  3. Requires a Professional (Business or Creator) Instagram account

LinkedIn

  1. Create an app at developer.linkedin.com
  2. Add the Share on LinkedIn and Sign In with LinkedIn using OpenID Connect products
  3. Set redirect URI to https://your-domain/auth/linkedin/callback

Mastodon

  1. Log in to your Mastodon instance → Settings → Development → New Application
  2. Scopes: read:accounts, write:statuses, write:media
  3. Set redirect URI to https://your-domain/auth/mastodon/callback

Works with any Mastodon-compatible instance mastodon.social, fosstodon.org, hachyderm.io, etc.

YouTube

  1. Create a project in Google Cloud Console
  2. Enable the YouTube Data API v3
  3. 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

  1. Use the same Meta app as Threads/Instagram
  2. Add Manage everything on your Page use case
  3. Set redirect URI to https://your-domain/auth/facebook/callback
  4. Requires a Facebook Page personal profiles are not supported by the Graph API

First comment support requires pages_manage_engagement (pending Meta app review).

Pinterest

  1. Create an app at developers.pinterest.com
  2. Enable scopes: boards:read, pins:read, pins:write, user_accounts:read
  3. Set redirect URI to https://your-domain/auth/pinterest/callback
  4. Set PINTEREST_CLIENT_ID and PINTEREST_CLIENT_SECRET in .env

Trial access (default): New apps get Trial access pins can only be created in the sandbox.

  • Set PINTEREST_SANDBOX=true
  • Generate a sandbox token: My Apps → Manage → Generate Access Token → Sandbox
  • Set PINTEREST_SANDBOX_TOKEN to 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)

  1. Create a project + app at developer.x.com
  2. Set App permissions to Read and write
  3. Enable OAuth 1.0a and set the callback URL to https://your-domain/auth/twitter/callback
  4. Copy 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.

  1. Open Telegram and message @BotFather/newbot → follow the prompts to get a bot token
  2. Create a Telegram channel (public or private)
  3. Add your bot to the channel as an Administrator with at least the Post Messages permission
  4. Go to Accounts in Posthive → Connect Telegram Channel
  5. 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.

  1. Go to Accounts in Posthive → Connect Nostr
  2. Paste your nsec1... private key — or click Generate a new keypair to create a fresh one
  3. Your profile name and photo are fetched automatically from relays

Your nsec is 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.

  1. Go to discord.com/developersNew Application → name it Posthive
  2. Go to Bot tab → Add Bot → copy the bot token
  3. Go to OAuth2 → General → copy Client ID and Client Secret → add redirect URI
  4. 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"
  1. 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.

  1. Go to tumblr.com/oauth/appsRegister application (instant, no review)
  2. Set Default callback URL to https://your-domain.com/auth/tumblr/callback
  3. Add to .env:
TUMBLR_CONSUMER_KEY="your-consumer-key"
TUMBLR_CONSUMER_SECRET="your-consumer-secret"
TUMBLR_REDIRECT_URI="https://your-domain.com/auth/tumblr/callback"
  1. 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.

  1. Create a Lemmy account on any instance (e.g. lemmy.world, lemmy.ml, beehaw.org)
  2. Go to Accounts in Posthive → Connect Lemmy
  3. Enter your instance URL, username, password, and the community to post to (e.g. [email protected])

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

Accounts column syntax:

  • all - all connected accounts except YouTube
  • bluesky|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

  1. Write a post in Compose, pick accounts, set a time
  2. API creates a PostJob in the DB and enqueues a BullMQ delayed job
  3. At the scheduled time BullMQ fires the job (~1 second accuracy)
  4. The worker processes each platform independently:
    • Refreshes OAuth tokens if needed
    • Posts the main content
    • Posts the first comment as a reply (if provided)
  5. Each step is persisted before the next crash-safe and resumable
  6. 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_failed

Post Templates

Save and reuse post drafts from the Compose page:

  1. Write a post and click + Save in the POST section header
  2. Give it a name (must be unique)
  3. Click Templates to open the dropdown and load any saved template
  4. 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_key

Endpoints:

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)

  1. Claude: Settings → Connectors → Add custom connector. ChatGPT: Settings → Apps → Advanced settings → enable Developer mode, then Settings → Apps → Add app.
  2. Enter https://your-api/mcp
  3. Approve access in the browser prompt that opens

Claude Code

claude mcp add --transport http posthive https://your-api/mcp

The 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_2

Every 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_accounts List all connected social accounts
create_post Create a scheduled or draft post
get_post Get a single post by ID
list_scheduled_posts List posts with optional status filter
approve_draft Promote a draft to scheduled
update_post Update content or reschedule a pending post
duplicate_post Clone a post as a new draft
delete_post Delete a post
list_templates List saved post templates
create_from_template 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
Instagram 2,200 characters
LinkedIn 3,000 characters
Mastodon 500 characters
YouTube Title: 100 · Description: 5,000
Facebook Pages 63,206 characters
Pinterest 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=false

All features are unlocked for all users. No Dodo account needed. Onboarding skips plan selection.

With billing:

ENABLE_BILLING=true
NEXT_PUBLIC_ENABLE_BILLING=true

Create 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

  1. Create a project at supabase.com
  2. Storage → create a bucket named media → set it to Public
  3. Settings → Database → Connection String → Session pooler (port 5432) → copy URI

2. Railway - API

  1. New project → Deploy from GitHub → Root Directory: leave blank (repo root)
  2. Add a Redis service → copy private URL as ${{ Redis.REDIS_URL }}
  3. Set environment variables (see table above)
  4. Builder: Railpack (default — do not switch to Dockerfile)
  5. Build Command:
    pnpm install --frozen-lockfile --filter api... && pnpm --filter api exec prisma generate && pnpm --filter api build
    
  6. Start Command:
    cd apps/api && npx prisma migrate deploy && node dist/index.js
    
  7. Add custom domain → set port to 3001

3. Vercel - Frontend

  1. Import same repo → Root Directory: apps/web
  2. Add env vars: NEXT_PUBLIC_API_URL and NEXT_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 dev locally.


Adding a New Platform

  1. Create apps/api/src/adapters/<platform>.ts implementing PlatformAdapter
  2. Register in apps/api/src/adapters/index.ts
  3. Add OAuth routes in apps/api/src/routes/auth.ts
  4. Add platform card in apps/web/src/app/accounts/page.tsx — also add to PLATFORM_META and RECONNECT_URLS
  5. Add favicon domain in apps/web/src/components/PlatformIcon.tsx
  6. Add PLATFORM_COLOR and PLATFORM_LIMIT in apps/web/src/components/PlatformPreview.tsx
  7. Add preview component in apps/web/src/components/PlatformPreview.tsx
  8. Add to PLATFORMS_GRID in apps/web/src/app/page.tsx (landing page grid + hero card)
  9. Add to PLATFORMS_NAV in apps/web/src/components/LandingNav.tsx
  10. Add platform data object in apps/web/src/app/platforms/[platform]/page.tsx
  11. Add docs section in apps/web/src/app/docs/page.tsx
  12. Add to NO_COMMENT_PLATFORMS in compose, EditPostDialog, and jobRunner.ts if the platform has no comment API
  13. Add env vars to apps/api/.env.example and document in this README

Community

Join the Posthive Discord for support, feature requests, and to connect with other users:

discord.gg/Ynv8TKRX


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.

from github.com/AstaBlackClove/posthive

Installing Posthive

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/AstaBlackClove/posthive

FAQ

Is Posthive MCP free?

Yes, Posthive MCP is free — one-click install via Unyly at no cost.

Does Posthive need an API key?

No, Posthive runs without API keys or environment variables.

Is Posthive hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Posthive in Claude Desktop, Claude Code or Cursor?

Open Posthive on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Posthive with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All communication MCPs