postwire · git:20260829.59c13ca · 2026-08-29 · sha256 32c0ca67dd3996e7
postwire git:20260829.59c13caA
Immutable. This exact content is served forever at /api/v1/blob/32c0ca67dd3996e7.
---
name: postwire
category: social-media
description: "Publish and schedule to TikTok, Instagram, YouTube, LinkedIn, X, Bluesky, Mastodon, Facebook, Threads, Reddit, Telegram and Discord through one PostWire API call — writing a separate, native version of the post for each network instead of sending identical text everywhere. Use when the user wants to publish or schedule one idea across several platforms, wants per-network captions, or wants to know why a post was rejected before it is sent."
license: MIT
requires:
env: [POSTWIRE_API_KEY]
---
# PostWire
Publish one idea to many social networks, with a **different post written for each one**.
Accounts are connected once through OAuth in the PostWire dashboard, so there is no per-platform
developer app, review queue, or token refresh to maintain. One API key covers every network.
## When to Use This Skill
- The user wants the same idea published to several networks, but written properly for each
- The user wants a post scheduled for later, or a week of posts queued from one topic
- The user asks why a post failed, or whether a post *will* fail before sending it
- The user is publishing video to TikTok or YouTube from an automation
## What Makes This Different
Most multi-posting APIs take one string and send it to every platform. That reads badly and gets
suppressed: a LinkedIn post written like a tweet performs like neither. PostWire has a `/api/generate`
step that writes a caption per network — length, tone, hashtags and link handling — from a single
prompt, which you then pass to publish or schedule.
It also **refuses posts that are going to fail**, before they are queued rather than after the
platform rejects them:
| network | requires |
|---|---|
| TikTok, YouTube | a video (`video_url`) |
| Instagram | a photo or a video |
| everything else | text is enough |
## Prerequisites
- An account at [postwire.io](https://postwire.io) — free tier: 1 brand, 30 posts/month, no card
- Networks connected in the dashboard (one OAuth click each)
- `POSTWIRE_API_KEY` in the environment
**Auth is `Authorization: Bearer $POSTWIRE_API_KEY`.**
One gotcha worth knowing: the dashboard shows a *preview* key immediately after signup, before the
email is confirmed. That key cannot publish. If the API answers `"This is a preview key"`
(`code: "preview_key"`), confirm the email and take the key from **API & MCP** in the dashboard.
## How to Use
Base URL: `https://postwire.io/api`
### Check what is connected
```bash
curl https://postwire.io/api/me -H "Authorization: Bearer $POSTWIRE_API_KEY"
```
Returns the plan, the monthly usage, and `connections[]` — publish only to networks listed there,
otherwise the call fails with `code: "not_connected"` and the offending platforms.
### Write a native caption per network
```bash
curl -X POST https://postwire.io/api/generate \
-H "Authorization: Bearer $POSTWIRE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "We shipped streaming uploads: 1GB videos now go through in 11 seconds",
"platforms": ["linkedin", "x", "bluesky"]
}'
```
Returns `{ "drafts": { "linkedin": {...}, "x": {...}, "bluesky": {...} } }`. Pass that object
straight through as `per_platform` below.
### Publish now
```bash
curl -X POST https://postwire.io/api/post \
-H "Authorization: Bearer $POSTWIRE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["linkedin", "x"],
"per_platform": { "linkedin": {"text": "..."}, "x": {"text": "..."} }
}'
```
Without `per_platform`, a single `text` is used everywhere — simpler, but it is the behaviour this
tool exists to avoid.
The response is **per platform**, and one failure does not cancel the rest:
```json
{ "results": [ { "ok": true, "platform": "linkedin", "id": "..." },
{ "ok": false, "platform": "x", "error": "..." } ] }
```
### Schedule instead
```bash
curl -X POST https://postwire.io/api/schedule \
-H "Authorization: Bearer $POSTWIRE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"run_at": "2026-09-01T09:00:00Z",
"platforms": ["linkedin", "instagram"],
"photo_url": "https://example.com/image.jpg",
"label": "Launch announcement"
}'
```
`run_at` is ISO 8601. The schedule endpoint validates connections *and* the media rules up front, so
a post that cannot work is rejected now instead of failing quietly at 7am.
### Fill a week from one topic
```bash
curl -X POST https://postwire.io/api/week \
-H "Authorization: Bearer $POSTWIRE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "topic": "what we learned running a one-person SaaS", "platforms": ["linkedin", "x"], "days": 5 }'
```
Five angles on one topic, queued across five days. Text-only networks only — the video platforms
would reject every one of them, and the endpoint says so rather than queueing them to fail.
## Errors Worth Handling
| code | meaning | fix |
|---|---|---|
| `preview_key` | key from before email confirmation | confirm email, use the key in API & MCP |
| `email_unverified` | mailbox not confirmed yet | open the emailed link |
| `not_connected` | platform not connected; `platforms[]` lists which | connect it in the dashboard |
| `media_required` | TikTok/YouTube without video, Instagram without media | add `video_url` or `photo_url` |
| 429 | monthly plan limit or a burst guard | check `usage` in `/api/me` |
## Media Notes
- Media is passed by URL (`video_url`, `photo_url`); PostWire fetches and forwards the bytes.
- TikTok and YouTube videos are streamed in chunks, so they can be up to **1GB**. Other networks and
hosts that do not send `Content-Length` are capped at 80MB, because the file has to be held in memory.
- `POST /api/media/upload-url` returns a signed URL to upload a file directly (max 50MB) if you do
not have somewhere to host it.
## Also Available
PostWire ships an **MCP server**, so an agent can call these as tools rather than as HTTP requests,
and there are n8n templates for the same flows. Both are linked from the dashboard.