How to post to social media with Python
requests.post to https://postwire.io/api/post with your PostWire key and a list of networks: {"platforms": ["linkedin", "bluesky"], "text": "…"}. PostWire publishes to each network through its official API and answers with one result per network: ok, the post's url, or an error with a code your script can branch on. Nothing to install beyond requests, and the free plan covers it: 1 business, 20 posts a month, 5 AI drafts a day, 2 networks per post, no card.Connect each account once in the dashboard (TikTok, Instagram, YouTube, LinkedIn, Facebook Pages, Bluesky, Mastodon, Telegram, Discord, and X on paid plans), and your script never handles a network's tokens, app review or API changes.
Updated . Written from PostWire's own code; vendor prices read on Oct 15, 2026. Live networks: TikTok, Instagram, YouTube, LinkedIn (personal profiles), Facebook Pages, Bluesky, Mastodon, Telegram, Discord, and X on paid plans.
From zero to a published post, step by step
Set your key in the environment first: export POSTWIRE_API_KEY=pw_live_…. Every example below reads it from there.
- Create a free account and copy your key
Open the dashboard, sign in with your email and a 6-digit code (no password, no card), and copy your key under API & MCP. It starts with
pw_live_and goes in theAuthorization: Bearerheader. - Connect the accounts you post to
Under Accounts, press Connect on each network; TikTok, Instagram, YouTube, LinkedIn and Facebook sign in on their own page, Telegram, Discord, Bluesky and Mastodon take a token or webhook. Your script can check them with
GET /api/me. - Publish a post
One request, one result per network. The
idempotency_keymakes a retry safe: send the same key again after a timeout and the post is not published twice.import os, uuid, requests API = "https://postwire.io/api" HEAD = {"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"} key = str(uuid.uuid4()) # keep it for retries of this same post r = requests.post(f"{API}/post", headers=HEAD, timeout=120, json={ "platforms": ["linkedin", "bluesky"], "text": "We cut our CI time from 9 minutes to 2. Here is what changed.", "idempotency_key": key, }) for res in r.json().get("results", []): print(res["platform"], res.get("url") if res["ok"] else (res.get("code"), res.get("error"))) - Let the API write each network's version
POST /api/generateturns one idea into a post written for each network and publishes nothing. Pass itsdraftsstraight back asper_platform.drafts = requests.post(f"{API}/generate", headers=HEAD, timeout=120, json={ "prompt": "Our new pricing page is live: plans from $9, a free plan with no card", "platforms": ["linkedin", "bluesky"], }).json()["drafts"] requests.post(f"{API}/post", headers=HEAD, timeout=120, json={ "platforms": list(drafts), "per_platform": drafts, }) - Upload a video or photo from disk
Three calls: ask for an upload URL, PUT the bytes there (they never pass through the API), and finalize to get a
media_url. One PUT takes up to 50 MB; larger files are sent in parts with"multipart": true.path = "clip.mp4" up = requests.post(f"{API}/media/upload-url", headers=HEAD, json={ "content_type": "video/mp4", "size_bytes": os.path.getsize(path), }).json() with open(path, "rb") as f: requests.put(up["upload_url"], data=f, headers={"Content-Type": "video/mp4"}).raise_for_status() media = requests.get(f"{API}/media/finalize", headers=HEAD, params={"path": up["path"]}).json() requests.post(f"{API}/post", headers=HEAD, timeout=300, json={ "platforms": ["tiktok", "youtube"], "video_url": media["media_url"], "text": "CI in 2 minutes, start to finish", "per_platform": {"youtube": {"title": "CI in 2 minutes", "text": "How we did it"}}, }) - Schedule instead of posting now
POST /api/scheduletakes the same body plusrun_at: an ISO time up to 365 days ahead, or"next_slot"for the brand's next free posting hour. PostWire publishes it at that time; your script can exit.requests.post(f"{API}/schedule", headers=HEAD, json={ "platforms": ["linkedin", "bluesky"], "text": "Office hours this Friday at 4pm.", "run_at": "2026-10-23T09:00:00-04:00", })
Every endpoint, field and error code: API reference and openapi.json. Prefer no code? The same calls run from the n8n node or from an AI agent through the MCP server.
Posting from Python: PostWire, Upload-Post and Ayrshare
What each needs in a Python project and what it costs to start, read on each vendor's own Python and pricing pages on Oct 15, 2026.
| Service | In Python | Auth header | Free to start | Cheapest paid plan | Writes each network's text |
|---|---|---|---|---|---|
| PostWire | requests — no package to install | Authorization: Bearer pw_live_… | Free plan: 1 business, 20 posts a month, 5 AI drafts a day, 2 networks per post, no card, TikTok included | $9/mo — 3 businesses, every network in each post | Yes — POST /api/generate |
| Upload-Post | pip install upload-post, or requests | Authorization: Apikey … | Free plan: 10 uploads a month, without TikTok | $24/mo — 5 profiles | Not listed |
| Ayrshare | The Social-Post-API package on PyPI | Not listed | 28-day free trial of the Launch plan | $149/mo billed monthly — Premium, 1 social profile | Not listed |
Checked on Oct 15, 2026 (2026-10-15) on each vendor's own pricing or docs page, linked in the first column and below. Monthly billing in USD unless noted. "Not listed" means we could not find it on their page, not that it is missing.
Where PostWire is ahead
- A free plan with TikTok in it: 20 posts a month, no card and no time limit. Upload-Post's free plan has 10 uploads a month without TikTok; Ayrshare starts with a 28-day trial.
- The cheapest paid plan here: $9 a month for 3 businesses. Upload-Post Basic is $24 and Ayrshare Premium $149, both billed monthly.
- The API writes the posts too:
POST /api/generateturns one idea into a LinkedIn post, an X post, a TikTok caption and a YouTube title, each written for its network, ready forper_platform. - Retries that never post twice: send the same
idempotency_keyafter a timeout and the post goes out once. - Nothing to install or keep updated: three endpoints and a Bearer header, with the full
openapi.jsonto generate a client if you want one.
- Upload-Post — How to automate social media posting with Python (pip install upload-post; Authorization: Apikey header): www.upload-post.com/how-to/automate-social-media-posting-with-python/
- Upload-Post plans (llms-full.txt: Free 10 uploads a month, without TikTok; Basic $24 a month, 5 profiles): www.upload-post.com/llms-full.txt
- Ayrshare — PyPI integration (the Social-Post-API package; "supports Premium, Business, and Enterprise"): www.ayrshare.com/integration/pypi/
- Ayrshare pricing (Premium $149/mo billed monthly; a 28-day free trial of the Launch plan, $299/mo): www.ayrshare.com/pricing/
Handling the answer in your script
- Check each network, not only the status code: one request can publish on LinkedIn and fail on Bluesky.
postedcounts the networks that went out, and each item ofresultshasok. - Branch on
code, not on the English message:not_connected(connect it in the dashboard),rate_limitedwithretry_afterin seconds,networks_per_postwithheld: true(the free plan sends one post to 2 networks and holds the rest, spending nothing on them). - Several businesses: with the same network connected in more than one brand, pass
brand_id(fromGET /api/brands); without it the API answers 409ambiguous_brandand publishes nothing. - Video can finish later: a result with
status: "processing"is accepted; follow it withGET /api/post/status.
Source: PostWire's OpenAPI document and server code, read Oct 15, 2026.
What it does not do
PostWire has no Python package of its own: the REST API is small enough for requests (or httpx). It does not post to Threads, Reddit or Pinterest, to LinkedIn company pages or to personal Facebook profiles, and X is on paid plans only. Files sent by URL must be public https links.
Questions people ask
Can I post to Instagram and TikTok with Python?
Yes. Connect the accounts once in PostWire's dashboard, then send one requests.post to https://postwire.io/api/post with "platforms": ["instagram", "tiktok"] and a video_url or photo_url. PostWire publishes through Instagram's and TikTok's official APIs; Instagram needs a Business or Creator account.
Do I need a developer account for each network?
No. PostWire's own apps with TikTok, Meta, YouTube and LinkedIn do the publishing, so your script needs only a PostWire key. Telegram, Discord, Bluesky and Mastodon connect with a bot token, webhook or app password you paste in the dashboard.
Is there a PostWire Python SDK?
No, and none is needed: the REST API takes JSON and a Bearer header, so requests or httpx is enough. openapi.json describes every endpoint if you prefer to generate a typed client.
How do I schedule posts from Python?
POST to https://postwire.io/api/schedule with the same body as /api/post plus run_at, an ISO 8601 time up to 365 days ahead or "next_slot". PostWire stores the post and publishes it at that time, so the script can exit.
How do I upload a local video?
POST /api/media/upload-url with content_type and size_bytes, PUT the file to the upload_url it returns, then GET /api/media/finalize?path=… for a media_url, and pass it as video_url. One PUT takes up to 50 MB; larger files go in parts.
Is it free?
Yes, to start: 1 business, 20 posts a month, 5 AI drafts a day, 2 networks per post, no card, with the REST API included. Starter is $9 a month for 3 businesses and Pro $29 for 10, with every network in each post; paid plans have a 14-day refund.
Try it on one business, free.
The free plan is 1 business, 20 posts a month, 5 AI drafts a day (about 20 a month) and 2 networks per post — every network connects free, no card, no time limit. Paid plans start at $9 a month and have a 14-day refund; Pro can be tried free for 7 days, with a card at checkout and nothing charged that day.