Publish

Publish one post to one or many networks now, and check a post's status.

View as MarkdownOpenAPIBase URL https://postwire.io

One request publishes to every network you name, in parallel. Each network gets its own result, so one failing never fails the others. posted counts the networks that went out. Send per_platform drafts (from AI writing) to publish a different native text on each network, and options for the per-network options.

Post (or cross-post) to one or more platforms

POST/api/post

Needs an API key: Authorization: Bearer pw_live_….

Body (JSON)

FieldTypeDescription
platformstringSingle platform; or use 'platforms'.
platformsarray of stringCross-post to many at once, in parallel.
textstringCaption / description.
titlestringTitle (used by YouTube).
video_urlstringURL of the video to post (required for YouTube; TikTok takes a video or photos).
photo_urlstringURL of one image. TikTok posts it as a photo post. Instagram and TikTok take JPEG (TikTok also WebP): PostWire converts PNG, WebP, AVIF and still GIF to JPEG automatically; animated GIF and HEIC are refused.
privacystringe.g. private | public | unlisted (YouTube).
mediaarray of objectSeveral images (or images and videos) in one post, in order. Instagram: a carousel of up to 10 (images and MP4 videos). TikTok: a photo post of up to 35 images. PNG (and WebP, AVIF, still GIF) is converted to JPEG automatically for Instagram and TikTok. Bluesky: up to 4 images. Mastodon: up to 4. LinkedIn: up to 20 images, or one document (PDF/PPT/DOC). Networks that take one item get the first, and the result says so. Also accepted inside a per_platform draft. Up to 35 items.
media[].url requiredstringPublic https URL of the file.
media[].typestringOne of: image, video, document. Default "image".
media[].altstringAlt text (Bluesky, Mastodon, LinkedIn).
media[].titlestringDocument title (LinkedIn).
photo_urlsarray of stringShorthand for media: a list of image URLs.
per_platformobjectPer-network overrides, keyed by network name (e.g. {"tiktok":{"text":"…"},"youtube":{"title":"…","text":"…"}}). Each value may carry text, title, video_url, photo_url, media and network options.
optionsobject (see Network options)Options per network, keyed by network name. See Network options.
brand_idstringBrand whose connected accounts publish this post (GET /api/brands). Defaults to the account's only brand.
idempotency_keystringSend the same key on a retry and the post is not published twice.

Responses

StatusMeans
200One result per network. Check `posted` and each `results[].ok`. Each result carries account { platform, handle, display_name, brand_id, brand, label } and published_to names every account reached. With the same network in more than one brand and no brand_id: 409 ambiguous_brand, nothing published. On a plan with a networks-per-post limit (Free: 2) the first networks that pass their checks are published and the others come back held (code networks_per_post), listed in held_networks with held_message and an upgrade link: a partial publish is a 200 that says what it held back.
400Bad request
401Missing or invalid API key
403Email not verified, or the key is read-only
curl
curl -X POST "https://postwire.io/api/post" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platforms": [
    "bluesky",
    "linkedin",
    "telegram"
  ],
  "text": "Our sourdough now proofs for 36 hours. Here is what changed in the crumb.",
  "idempotency_key": "bakery-2026-10-03-sourdough"
}'
Node
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",
      "linkedin",
      "telegram"
    ],
    "text": "Our sourdough now proofs for 36 hours. Here is what changed in the crumb.",
    "idempotency_key": "bakery-2026-10-03-sourdough"
  }),
});
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", "linkedin", "telegram"],
        "text": "Our sourdough now proofs for 36 hours. Here is what changed in the crumb.",
        "idempotency_key": "bakery-2026-10-03-sourdough",
    },
)
print(r.status_code, r.json())

Example response

JSON
{
  "posted": 3,
  "published_to": "Published to @bakery.bsky.social (Bakery) on bluesky, Ana Ruiz (Bakery) on linkedin, chat @bakerynews (Bakery) on telegram.",
  "results": [
    {
      "ok": true,
      "platform": "bluesky",
      "id": "at://did:plc:4x2…/app.bsky.feed.post/3l7…",
      "url": "https://bsky.app/profile/bakery.bsky.social/post/3l7…",
      "account": {
        "platform": "bluesky",
        "handle": "bakery.bsky.social",
        "brand": "Bakery",
        "label": "@bakery.bsky.social (Bakery)"
      }
    },
    {
      "ok": true,
      "platform": "linkedin",
      "id": "urn:li:share:72…",
      "url": "https://www.linkedin.com/feed/update/urn:li:share:72…"
    },
    {
      "ok": true,
      "platform": "telegram",
      "id": "412",
      "url": "https://t.me/bakerynews/412"
    }
  ]
}

Each result also carries account, the connected account it went to. The second and third are shortened here.

Check the status of a created post

GET/api/post/status

Needs an API key: Authorization: Bearer pw_live_….

Parameters

FieldTypeDescription
platform requiredquery, string
id requiredquery, string

Responses

StatusMeans
200{ platform, id, status }
curl
curl "https://postwire.io/api/post/status?platform=instagram&id=igp_5d0c%E2%80%A6" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/post/status?platform=instagram&id=igp_5d0c%E2%80%A6", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.get(
    "https://postwire.io/api/post/status?platform=instagram&id=igp_5d0c%E2%80%A6",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Example response

JSON
{
  "platform": "instagram",
  "id": "igp_5d0c…",
  "status": "processing"
}