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.jsonfile. 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?
| Need | Use | Why |
|---|---|---|
| Multi-user account connection | Scheduler API | Users connect accounts in the web app. |
| Scheduling | Scheduler API | Scheduled posts are stored and dispatched later. |
| MCP for AI assistants | Scheduler API | MCP is hosted by the Scheduler app. |
| Simple backend-to-backend publishing | Self-hosted REST server | One API key, one account file, no app database. |
| Your own token store | Self-hosted REST server or SDK | You provide credentials directly. |
| Direct upload to S3/R2 | Either API | Both expose size-bound presigned PUT URLs. |
| Local disk media uploads | Self-hosted REST server | Serves 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
| Caller | Authentication |
|---|---|
| Hosted/custom Scheduler API integration | Authorization: Bearer <user-managed API key> |
| Scheduler browser UI | Signed-in session |
| Scheduler CLI | CLI-issued bearer token |
| Remote MCP | OAuth bearer token |
| Standalone REST server | x-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
thumbnailUrlafter uploading a custom thumbnail. - Support CLI authorization.
- Support OAuth and MCP endpoints.
Useful routes:
| Route | Purpose |
|---|---|
/api/v1/accounts | List connected accounts. |
/api/v1/posts | Create, 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/upload | Server-side media upload. |
/api/v1/upload/presign | Direct S3/R2 upload URL generation bound to the declared filename, media type, and byte size. |
/api/v1/validation | Validate a post draft. |
/api/cli/authorize | CLI connection flow. |
/api/oauth/* | MCP OAuth flow. |
/mcp | MCP 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 /healthGET /api/v1/accountsPOST /api/v1/uploadPOST /api/v1/upload/presignPOST /api/v1/validationPOST /api/v1/postsGET /media/:filenameGET /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:
| Variable | Required | Description |
|---|---|---|
SIMPLE_POST_API_KEY | Yes | Shared secret clients send as x-api-key. |
SIMPLE_POST_ACCOUNTS_FILE | Recommended | Path to accounts.json. Without it, posting rejects all accounts. |
SIMPLE_POST_PUBLIC_URL | Recommended | Public URL used for media URLs. |
SIMPLE_POST_STORAGE_DIR | No | Local uploaded media directory. |
S3_STORAGE_* | No | S3/R2 credentials, endpoint, bucket, and public media base URL. |
PORT | No | Defaults 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.