Skip to main content

API

SimplePost has two HTTP APIs with overlapping request shapes:

  • The Scheduler API is part of the Scheduler app. It uses connected accounts, user sessions, upload storage, scheduling, CLI auth, and the MCP OAuth flow.
  • The self-hosted REST server is a small stateless Express server around the SDK. It uses an API key and an accounts.json file. It publishes immediately and does not include users, scheduling, OAuth account connection, or MCP.

Use the same client-side posting model for both when possible, then choose the deployment based on account management and scheduling needs.

Which API should I use?

NeedUseWhy
Multi-user account connectionScheduler APIUsers connect accounts in the web app.
SchedulingScheduler APIScheduled posts are stored and dispatched later.
MCP for AI assistantsScheduler APIMCP is hosted by the Scheduler app.
Simple backend-to-backend publishingSelf-hosted REST serverOne API key, one account file, no app database.
Your own token storeSelf-hosted REST server or SDKYou provide credentials directly.
Direct upload to S3/R2Either APIBoth expose size-bound presigned PUT URLs.
Local disk media uploadsSelf-hosted REST serverServes uploaded files from /media/:filename.

Hosted API quickstart

Hosted API keys require Pro or an active free trial. First connect accounts in the web app, then open API Keys from the profile menu. Create a key and copy it once. Store it securely as SIMPLEPOST_API_KEY.

List actual connected account IDs:

curl "https://app.simplepost.social/api/v1/accounts" \
-H "Authorization: Bearer $SIMPLEPOST_API_KEY"

Save a draft using an ID from that response:

curl -X POST "https://app.simplepost.social/api/v1/posts" \
-H "Authorization: Bearer $SIMPLEPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Launching today!",
"accountIds": ["REPLACE_WITH_CONNECTED_ACCOUNT_ID"],
"postingMode": "draft",
"idempotencyKey": "launch-draft-unique-001"
}'

Use postingMode: "now" only when you intend to publish. Scheduling uses postingMode: "schedule" with a future scheduledFor including a timezone. Use a new idempotency key for each distinct create operation.

Authentication by surface

CallerAuthentication
Hosted/custom Scheduler API integrationAuthorization: Bearer <user-managed API key>
Scheduler browser UISigned-in session
Scheduler CLICLI-issued bearer token
Remote MCPOAuth bearer token
Standalone REST serverx-api-key: <SIMPLE_POST_API_KEY>

The standalone server's x-api-key header does not authenticate hosted Scheduler requests. Hosted CLI requires Advanced/Pro/trial; hosted MCP works on every paid plan and the trial. Local SDK/CLI and self-hosted publishing have no hosted subscription requirement.

Results and retries

Inspect post, postingResults, and summary per account. An accepted scheduled post has not yet published, and an overall failure can include successful targets. Read the record using GET /api/v1/posts/{id} before retrying.

After an uncertain response, reuse the same idempotency key and payload. Do not submit a new key merely because the response was lost. For a failed post, inspect its account results and retry only the intended failed targets. Where delivery is uncertain, inspect the platform and the reconciliation endpoint before creating another post. Recovery guide.

Use the API reference for webhooks, posting slots, repost settings, creator information, YouTube library operations, and post reconciliation. Post counting and expiry.

Scheduler API

Use the Scheduler API when you run the Scheduler app or use the hosted Scheduler at app.simplepost.social.

Main capabilities:

  • List connected accounts.
  • Upload media through the server or presigned storage URLs.
  • Validate posts against selected accounts.
  • Publish now.
  • Schedule for later.
  • Inspect drafts, scheduled, posted, and failed posts.
  • Update or delete drafts and scheduled posts.
  • Set per-account platform options, such as YouTube thumbnailUrl after uploading a custom thumbnail.
  • Support CLI authorization.
  • Support OAuth and MCP endpoints.

Useful routes:

RoutePurpose
/api/v1/accountsList connected accounts.
/api/v1/postsCreate, list, save drafts, publish, or schedule posts.
/api/v1/posts/{id}Inspect, update, publish, schedule, draft, or delete one post when supported by its status.
/api/v1/uploadServer-side media upload.
/api/v1/upload/presignDirect S3/R2 upload URL generation bound to the declared filename, media type, and byte size.
/api/v1/validationValidate a post draft.
/api/cli/authorizeCLI connection flow.
/api/oauth/*MCP OAuth flow.
/mcpMCP Streamable HTTP endpoint.

The Scheduler app also exposes internal dispatch for scheduled posts. Call it only from trusted infrastructure:

curl -X POST "$NEXT_PUBLIC_APP_URL/api/internal/scheduled-posts/dispatch" \
-H "Authorization: Bearer $SCHEDULED_POST_DISPATCH_SECRET"

Self-hosted REST server

Use the REST server when you want a small HTTP wrapper around the SDK without running the full Scheduler app.

What it includes:

  • GET /health
  • GET /api/v1/accounts
  • POST /api/v1/upload
  • POST /api/v1/upload/presign
  • POST /api/v1/validation
  • POST /api/v1/posts
  • GET /media/:filename
  • GET /openapi.json

What it does not include:

  • Scheduling.
  • Account connection UI.
  • OAuth callback flows.
  • Multi-user sessions.
  • Database persistence.
  • MCP.

First standalone request

The standalone server has its own API key and account IDs from accounts.json:

curl -X POST "$SIMPLEPOST_BASE_URL/api/v1/posts" \
-H "Content-Type: application/json" \
-H "x-api-key: $SIMPLE_POST_API_KEY" \
-d '{"message":"Launching today!","accountIds":["telegram-news"],"postingMode":"now"}'

This publishes immediately. The standalone server does not support drafts or scheduling.

Configure the server

cd core
yarn install
cp server/.env.example server/.env

Set:

VariableRequiredDescription
SIMPLE_POST_API_KEYYesShared secret clients send as x-api-key.
SIMPLE_POST_ACCOUNTS_FILERecommendedPath to accounts.json. Without it, posting rejects all accounts.
SIMPLE_POST_PUBLIC_URLRecommendedPublic URL used for media URLs.
SIMPLE_POST_STORAGE_DIRNoLocal uploaded media directory.
S3_STORAGE_*NoS3/R2 credentials, endpoint, bucket, and public media base URL.
PORTNoDefaults to 3000.

Use POST /api/v1/upload/presign with filename, contentType, and size to obtain a 15-minute PUT URL plus a ready-to-use media object. PUT the exact bytes with the returned Content-Type, then pass media to validation or posting. Browser clients require a bucket CORS rule allowing PUT and Content-Type from the exact client origin.

Minimal accounts.json:

{
"accounts": [
{
"id": "telegram-news",
"platform": "telegram",
"platformAccountId": "@your_channel",
"credentials": { "botToken": "123456:ABC..." }
}
]
}

Each account can also include label, username, profilePicture, provider options, and provider-specific credentials. See the platform pages and credential strategies.

Run locally

yarn workspace @simple-post/server dev

Run in production

yarn workspace @simple-post/server build
yarn workspace @simple-post/server start

Run with Docker

cd core
docker build -t simple-post-server -f server/Dockerfile .

docker run -p 3000:3000 \
-e SIMPLE_POST_API_KEY=your-secret-api-key \
-e SIMPLE_POST_PUBLIC_URL=https://posts.example.com \
-e SIMPLE_POST_ACCOUNTS_FILE=/config/accounts.json \
-e SIMPLE_POST_STORAGE_DIR=/data \
-v /path/on/host/accounts.json:/config/accounts.json:ro \
-v simple-post-data:/data \
simple-post-server

API reference

Open API reference for the generated OpenAPI reference. It includes the Scheduler API and the self-hosted REST server API.