Postfalcon API
A small REST API for managing connected accounts and scheduled posts — the same API the built-in MCP server uses, available for your own scripts and agents.
Authentication
Generate a personal API token from Settings → API access for agents (you'll need an account first). Send it as a bearer token on every request:
Authorization: Bearer pf_<your token>
A token is shown once at creation time. Generating a new one immediately invalidates the old one.
Base URL & versioning
All endpoints below live under /api/v1. This prefix is a stability guarantee —
existing fields and behavior won't change under v1; a breaking change would ship as
/api/v2 instead, so integrations built against v1 keep working.
Rate limits & CORS
Requests are limited to 300 per 15 minutes, per token. Limit status is reported via the standard RateLimit-* response headers.
The /api/v1 API is CORS-enabled for any origin, so it can be called directly from a browser-based tool using a token — not just server-to-server.
Endpoints
| Method & path | Description |
|---|---|
GET /api/v1/social-accounts | List your connected social accounts. needs_reconnect_at / reconnect_reason are set when the platform rejected the account's credentials (posts to it will fail until it's reconnected); expires_soon is true when a non-refreshable token expires within 7 days |
POST /api/v1/social-accounts | Connect an account (platform, display_name, ...) |
DELETE /api/v1/social-accounts/:id | Disconnect an account |
GET /api/v1/posts | List posts — filter with ?status= and ?social_account_id= |
GET /api/v1/posts/:id | Get a single post |
POST /api/v1/posts | Create a draft or scheduled post (social_account_id or social_account_ids, content, optional scheduled_for or publish_now: true (published on the next scheduler run, within a minute), repeat_interval, repeat_until, tiktok_options, youtube_options) |
PATCH /api/v1/posts/:id | Update a post's content, status, schedule, repeat settings, tiktok_options, or youtube_options; publish_now: true sends a draft out within a minute |
DELETE /api/v1/posts/:id | Delete a post |
GET /api/v1/analytics/summary | Posts, views, likes, comments and shares for posts published in a period (?days=7|30|90, default 7; ?tz= an IANA timezone for day buckets, default UTC): per-day series, per-platform breakdown, top posts, plus all-time totals. A metric is null when no post in scope reports it. |
GET /api/v1/webhooks | List your webhook endpoints (Team & Pro plans) |
POST /api/v1/webhooks | Register an endpoint (url, optional events) — returns the signing secret once |
DELETE /api/v1/webhooks/:id | Remove a webhook endpoint |
Cross-posting
Pass social_account_ids (a JSON array, or a repeated form field) instead of
social_account_id to publish the same content to several channels at once. Postfalcon
creates one post per channel, all sharing a crosspost_group_id, and the response is
{ "crosspost_group_id": "…", "posts": […] }. A single-channel request is
unchanged — it still returns the bare post object. Cross-posting requires a plan with the
capability (all current paid plans).
Repeated posts
Add repeat_interval (daily, weekly, or monthly)
to a scheduled post to make it recurring. Optionally set repeat_until (ISO 8601) to
stop after a date; otherwise it runs for up to a year. When an occurrence publishes, Postfalcon queues
the next one automatically with its own copy of any attached media.
TikTok settings
TikTok requires the person posting to choose each video's audience and interaction settings. Pass
tiktok_options (an object, or a JSON string in a multipart request) with
privacy_level (PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS,
FOLLOWER_OF_CREATOR, or SELF_ONLY), and the booleans
allow_comment, allow_duet, allow_stitch,
brand_organic (promoting yourself), and brand_content (a paid partnership,
which can't be SELF_ONLY). Every boolean defaults to false. It only applies
to the TikTok channels of a cross-post. A TikTok post without a privacy_level publishes
as SELF_ONLY with interactions off; a level TikTok no longer offers for the account fails
the post rather than being swapped for another.
YouTube settings
Pass youtube_options (an object, or a JSON string in a multipart request) with
title (up to 100 characters, no < or >),
privacy_status (public, unlisted, or private),
and made_for_kids (boolean, default false). The post's
content becomes the video description. Without a title the first
100 characters of the content are used, and without a privacy_status the video
uploads as private. Like tiktok_options, it only applies to the
YouTube channels of a cross-post.
Analytics
A few times a day, Postfalcon pulls fresh view/like/comment/share counts for your recently-posted
content straight from each platform's API and stores the latest snapshot on the post. Coverage
varies by platform: Bluesky, Facebook, Instagram, Mastodon, Threads, and YouTube report likes and
comments (YouTube and Threads also report views); Telegram and TikTok don't expose post metrics
through their APIs, so those posts stay unmetered. GET /api/v1/posts includes the raw
metric_views / metric_likes / metric_comments /
metric_shares / metrics_updated_at fields on every post (null
until a platform reports something); GET /api/v1/analytics/summary aggregates them into
a ready-to-chart response:
{
"days": [{ "date": "2026-09-09", "views": 412, "likes": 38, "comments": 5 }, ...],
"totals": { "views": 3120, "likes": 266, "comments": 41, "shares": 9 },
"postsWithMetrics": 14,
"postsPosted": 16,
"topPost": { "id": 812, "platform": "youtube", "content": "...", "metric_views": 1204, ... }
}
Webhooks
Register an HTTPS endpoint and Postfalcon will POST it a JSON body whenever one of your
posts is published or fails:
{
"event": "post.published",
"sent_at": "2026-09-10T12:00:00.000Z",
"data": {
"post_id": 42,
"platform": "mastodon",
"platform_post_id": "109...",
"scheduled_for": "2026-09-10T12:00:00.000Z"
}
}
Events are post.published and post.failed (a failure payload carries
error instead of the platform id). Every request is signed so you can verify it came
from Postfalcon:
X-Postfalcon-Event: post.published
X-Postfalcon-Signature: sha256=<hex>
The signature is HMAC-SHA256(secret, rawRequestBody), hex-encoded. The secret is shown
once when you create the webhook. Deliveries time out after 8 seconds and are not retried;
the last delivery's timestamp and HTTP status are visible in Settings. Webhooks are available on
the Team and Pro plans.
Example
curl https://your-postfalcon-host/api/v1/posts \
-H "Authorization: Bearer pf_<your token>" \
-H "Content-Type: application/json" \
-d '{"social_account_id": 1, "content": "Hello from the API", "scheduled_for": "2026-08-01T12:00:00Z"}'
Errors
Errors are JSON with an error key, e.g. { "error": "not found" }. Validation failures use:
{ "error": "validation_failed", "details": { "fieldErrors": { "content": ["Required"] } } }
Any AI agent
Postfalcon ships an MCP
server built on this same API, in two forms depending on how your agent connects —
both expose the same 6 tools (list_accounts, list_posts,
create_post, update_post, delete_post,
get_analytics_summary):
-
A local command (Claude Desktop, Cursor's
command-style config, or any client that spawns a process): from a clone of the Postfalcon repo, runnode mcp/server.jswithPOSTFALCON_BASE_URLandPOSTFALCON_API_TOKENset to your host and token. -
A URL (ChatGPT, Claude.ai, Cursor's
url-style config, OpenClaw, or any other client that speaks Streamable HTTP): point it athttps://your-postfalcon-host/mcpwith your token as a standard bearer header — no local process to run.
Authorization: Bearer pf_<your token>
Not an MCP client? The plain REST API above works from anywhere that can make an HTTPS request with a bearer token — a Custom GPT Action, a script, or any other agent.