# PostWire API reference

> Publish one idea as a native post on each network, schedule it, and get told when it goes out. JSON over HTTPS at `https://postwire.io`. Every endpoint has a copyable example in curl, Node and Python.

Source: https://postwire.io/docs/ · Base URL: https://postwire.io · OpenAPI: https://postwire.io/openapi.json

## Quick start

1. **Get a key.** Sign up at [postwire.io](/dashboard.html?from=docs) and open **API & MCP**. Keys start with `pw_live_`. The Free plan includes the API.
2. **Connect a network.** Telegram, Bluesky, Mastodon and Discord with `POST /api/connect`; TikTok, YouTube, Instagram, Facebook Pages and LinkedIn with OAuth (`POST /api/oauth/{platform}/url`). Or in the dashboard.
3. **Publish.** One request, every network you name:

```bash
curl -X POST "https://postwire.io/api/post" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platforms": [
    "bluesky",
    "telegram"
  ],
  "text": "Hello from the PostWire API"
}'
```

```js
const res = await fetch("https://postwire.io/api/post", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "platforms": [
      "bluesky",
      "telegram"
    ],
    "text": "Hello from the PostWire API"
  }),
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/post",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "platforms": ["bluesky", "telegram"],
        "text": "Hello from the PostWire API",
    },
)
print(r.status_code, r.json())
```

## Authentication

Send the key in `Authorization: Bearer pw_live_…` (or `X-API-Key: pw_live_…`). A missing or wrong key answers 401. Publishing needs a verified email and a full-access key, otherwise 403. If PostWire cannot check a key because of its own outage it answers 503 `auth_unavailable`, never 401: retry, do not throw the key away.

Keys can be created with an expiry and revoked at once: see [Account, keys and billing](/docs/account/). `GET /api/platforms`, `GET /api/plans` and `GET /api/status` need no key.

## One result per network

Publishing answers 200 with `posted` (networks that went out) and `results[]`, one entry per network, each with `ok` and, when it did not go out, `error` and a machine-readable `code`. One network failing never fails the request or the others. A request-level problem (bad JSON, nothing connected, a network connected in two brands without `brand_id`) answers 4xx before anything is sent.

A post counts once **per network** that published: one idea to three networks is three of the month's posts. Networks refused before sending (not connected, held by the plan, media missing) spend nothing.

## Pages

| Page | What is in it |
|---|---|
| [Publish](/docs/publishing/) | Publish one post to one or many networks now, and check a post's status. |
| [Schedule and queue](/docs/scheduling/) | Queue posts for a time or for the next free slot, edit and cancel them, and fill a week from one topic. |
| [AI writing](/docs/ai-writing/) | Write a native post per network from one idea, without publishing. |
| [Media](/docs/media/) | Upload photos and videos up to 1 GB and get a URL to publish with. |
| [Networks and connections](/docs/connections/) | List networks, connect accounts (yours or your clients'), check and move connections. |
| [Brands](/docs/brands/) | Group each business's accounts and publish as that brand. |
| [Analytics (What works)](/docs/analytics/) | Your best posts against your own median, the patterns behind them, and drafts modelled on a winner. |
| [Webhook endpoints](/docs/webhooks-api/) | Register the URLs PostWire calls when a post publishes or fails. |
| [Account, keys and billing](/docs/account/) | Sign up, read usage and limits, manage API keys and the plan. |
| [Service status](/docs/status/) | The data behind the public status page, without an API key. |
| [Network options](/docs/network-options/) | Every option per network: TikTok privacy and labels, YouTube privacy and tags, Instagram and Facebook post types, LinkedIn first comment and documents, alt text. |
| [Errors, limits and idempotency](/docs/errors/) | Error shape, result codes, request rate limits, network rate limits, retries without duplicates. |
| [Webhooks guide](/docs/webhooks/) | Events, signature verification in Node.js and Python, retries. |
| [Schema changelog](/docs/schema-changelog/) | Every change to the API schema, by date, generated from the spec's history. |

## Plans and limits

From `GET /api/plans`, the same table the billing code reads. A post counts once per network.

| Plan | Price | Posts a month | Brands | AI drafts a day | Networks per post | Scheduled at a time |
|---|---|---|---|---|---|---|
| Free | $0 | 20 | 1 | 5 | 2 | 3 |
| Starter | $9/month | 300 | 3 | 60 | all | unlimited |
| Pro | $29/month | 2,000 | 10 | 300 | all | unlimited |
| Agency | $99/month | 15,000 | 50 | 1,500 | all | unlimited |
| Scale | $299/month | unlimited | 200 | 5,000 | all | unlimited |

Every plan includes the REST API, the MCP server, webhooks and TikTok. See [pricing](/pricing/).

## Machine-readable

- OpenAPI 3.0: [/openapi.json](/openapi.json).
- Every page of this reference as Markdown: add `.md` (for example [/docs/publishing.md](/docs/publishing.md)), or use the Markdown link at the top of each page.
- MCP server for Claude, ChatGPT and other agents: [/mcp/](/mcp/). For AI crawlers: [/llms.txt](/llms.txt).
