Everything lives under https://postwire.io/api/…. There is no version
prefix: /api/v1/me is not a thing, and calling it answers with a 404 that points
you at the right path. Authenticate with your key on every request:
curl https://postwire.io/api/me \
-H "Authorization: Bearer pw_live_…"
Your key is in the dashboard. Keys are per account and carry a scope; a full-scope key can publish.
| Endpoint | What it does |
|---|---|
GET /api/me | Plan, posts used this month, brands, connected networks. |
GET /api/brands | Your brands and which networks each one has connected. |
POST /api/generate | Writes a native draft per network. Returns drafts; publishes nothing. |
POST /api/post | Publishes. One result per network. |
POST /api/schedule | Queues for later. Rules are checked now, not at send time. |
GET /api/schedule | What is queued. |
GET /api/platforms | Every network and its limits. |
Full request and response schemas are in the OpenAPI spec.
The two calls that do the real work. Chain them and the drafts go out as written:
curl -X POST https://postwire.io/api/generate \
-H "Authorization: Bearer pw_live_…" -H "Content-Type: application/json" \
-d '{"prompt":"We shipped dark mode","platforms":["linkedin","bluesky","mastodon"]}'
# -> { "drafts": { "linkedin": {"text":"…"}, "bluesky": {"text":"…"}, … } }
curl -X POST https://postwire.io/api/post \
-H "Authorization: Bearer pw_live_…" -H "Content-Type: application/json" \
-d '{"platforms":["linkedin","bluesky","mastodon"],"per_platform":{…the drafts…}}'
Or skip the writer and send your own text with "text". Anything longer than a network
allows is trimmed to fit that network rather than rejected.
Publishing returns posted — how many networks actually went out — and one entry per
network in results. One network failing never fails the others.
{
"posted": 2,
"results": [
{"ok": true, "platform": "mastodon", "url": "https://…"},
{"ok": false, "platform": "tiktok", "code": "media_required",
"error": "tiktok needs a video…"}
]
}
| code | What to do |
|---|---|
not_connected | That network is not linked yet. Connect it in the dashboard. |
media_required | That network refuses text-only posts. Send video_url or photo_url. |
too_long | Only when you supplied that network's text yourself — your own words are never trimmed. |
empty_text | Nothing to publish: no text and no media. |
This is the rule people hit first, so it is worth knowing before you build:
| Network | Needs |
|---|---|
| TikTok, YouTube | A video. Text-only is rejected by the network itself. |
| An image or a video. | |
| LinkedIn, X, Facebook, Reddit, Bluesky, Mastodon, Telegram, Discord | Text alone is fine; media optional. |
Pass media as video_url or photo_url — two separate fields, so nothing has
to guess from a file extension. Both take a direct link.
Claude, Cursor and anything else that speaks MCP can drive PostWire directly. Point it at the hosted server with your key — setup per client is on the MCP page. After that you just ask: "post this to Mastodon and Discord", and the tool handles the rest.
There is a community node for n8n (n8n-nodes-postwire), and apps for
Make and Zapier. All three expose the same four actions: write and
publish, publish, schedule, and look up the account. The account lookup earns its place as a guard at
the top of a flow — it returns how many posts you have left before a loop spends them.
| Plan | Posts / month | Brands | AI drafts / day |
|---|---|---|---|
| Free | 30 | 1 | 15 |
| Starter | 300 | 3 | 60 |
| Pro | 2,000 | 10 | 300 |
| Agency | 15,000 | 50 | 1,500 |
A brand groups one business's accounts — its TikTok, its Instagram, its LinkedIn. A
solo operator with six networks uses one brand; an agency's clients are separate brands, each with
their own logins. Pass brand_id once you have more than one.
POST /api/schedule takes a run_at in the future and checks everything
immediately — the network being connected, the media being present. A post that would have failed
tomorrow morning fails now, while you are still looking at it.