Description
n8n-nodes-postwire
Publish one idea to every social network from n8n — with a different post written for each network, not the same text pasted everywhere.
This is the official n8n node for PostWire, maintained by the PostWire team. PostWire already holds the platform approvals TikTok, Instagram (Meta) and YouTube require for publishing apps, so connecting an account is one OAuth click — there is no developer app or App Review on your side.
Networks: TikTok · Instagram · YouTube · LinkedIn · Facebook · X (paid plans, X credits) · Bluesky · Mastodon · Telegram · Discord · Slack · Nostr — and articles on WordPress · Dev.to · Hashnode.
Two nodes:
- PostWire: publish, schedule, write drafts, and manage brands, connections, approvals and media.
- PostWire Trigger: start a workflow when a post is published or fails on a network, a connection needs signing in again, or a post waits for approval or gets a decision. Signed webhooks, registered and removed by the node.
Install
n8n Cloud and self-hosted — Settings → Community nodes → Install → n8n-nodes-postwire.
Self-hosted, from the command line:
cd ~/.n8n/nodes && npm install n8n-nodes-postwire
Credentials
1. Create a free account at approval", the approvalid, the post’s id and a review_url. Nothing is published until someone approves it. Follow it with Post → Get Status (Network: PostWire ID), Approval → Get, or a PostWire Trigger on Approval Decided.
PostWire Trigger
| Event | When |
|—|—|
| Post Published | A network accepted the post (one event per network), with its ID and link |
| Post Failed | A network refused it or it could not be sent, with the reason and a code |
| Connection Needs Sign-In | A network’s sign-in expired or was revoked, with the reconnect link |
| Approval Requested | A post is held for a person, with each network’s text as the approver sees it, the reasons and the dashboard link |
| Approval Decided | Someone approved or rejected it: the networks approved, rejected and edited, the reason, and when it goes out |
When the workflow is activated, the node adds a webhook endpoint to your PostWire account (POST /api/webhooks) for the events you picked and keeps its signing secret; when it is deactivated, it removes it. Every delivery is checked against the PostWire-Signature header (HMAC-SHA256 over , at most 5 minutes old) and refused with 401 if it does not match. Options → Networks and Brand ID narrow which events start the workflow. The output is the event (id, type, createdat, data) plus deliveryid, which stays the same on PostWire’s retries: dedupe on it.
PostWire calls n8n from the internet, so the instance needs a public https address (WEBHOOK_URL). A local http://localhost:5678 cannot receive events; the node says so when you activate it. An account has up to 5 endpoints. Send a test from PostWire (API & MCP → Webhooks → Send test): webhook.test always gets through. Events and payloads: postwire.io/docs/webhooks.
Media: the part that usually fails
TikTok and YouTube only publish video; Instagram needs a photo or a video. The networks download the file from a link, with no login — so the most common failure is a link that opens a page instead of the file.
https:// link straight to the .mp4/.jpg (up to 1 GB). Before anything is sent, the node checks the link the way the networks will: reachable without a login, a file and not a web page, under 1 GB, and a video when a video network is selected. Google Drive, Dropbox (dl=0), OneDrive and “link to a post” URLs are recognised and the error says exactly what to change.Nothing half-publishes, nothing double-posts
Output
Publish returns one item per network, so a Filter or IF node can act on failures alone:
{ "ok": true, "platform": "bluesky", "id": "at://…", "url": "https://bsky.app/profile/…/post/…" }
{ "ok": false, "platform": "youtube", "error": "…", "hint": "YouTube could not download the media. It must be a public https link…" }
If no network was published, the step fails (so a scheduled workflow cannot go silent for weeks), with the reason and the fix.
Write Drafts returns:
{
"drafts": { "linkedin": { "text": "…" }, "youtube": { "text": "…", "title": "…", "tags": ["…"] } },
"platforms": ["linkedin", "youtube"],
"preview": "LinkedInn…nnYouTuben…"
}
Map {{ $json.drafts }} into a later Publish with Content → Drafts From a Previous Step.
Errors say what to do
Every refusal from the API carries a code, and the node turns it into a message plus the fix:
| Code | What you see |
|—|—|
| not_connected | Which network, and where to connect it (or send a client a Connect Link) |
| media_required | Which network needs a video/photo, and how to add one |
| media_unreachable | Why PostWire could not download the file (403, 404, a Drive page…) — nothing was published |
| too_long | The limit and how far over it the text is |
| limitreached, brandlimit_reached | The plan limit and the upgrade link |
| duplicate_post | That the post was already sent moments ago and was not sent twice |
| xcreditsrequired, xpaidplanrequired, xdailylimit, badx_thread | What X needs (credits, a paid plan, tomorrow, a shorter post) — nothing was published |
| roleforbidden, brandrestricted, workspace_forbidden | The team role or brands of the member who created the key, and who can change them |
| keymonthlycapreached, keynetworknotallowed | A limit the owner set on this API key |
| nofreeslot | No free queue slot in 28 days: add slots or pick a time |
| 401 | Fix the API key in the credential |
| 429 | Daily AI-draft cap per plan, or a burst limit — wait or add a Wait node |
Examples
RSS → a native post per network
RSS Feed Trigger → PostWire: Post → Publish (Content: Smart Distribute, Idea: {{ $json.title }} — {{ $json.contentSnippet }} {{ $json.link }}, Networks: LinkedIn, Bluesky, Mastodon, Options → Idempotency Key: {{ $json.guid }}).
Google Drive video → TikTok, Reels and Shorts
Google Drive Trigger → Google Drive: Download → PostWire: Post → Publish (Media: Binary File, Networks: TikTok, Instagram, YouTube, Idea: {{ $json.name }}).
Approve in Slack before anything goes out
PostWire: Write Drafts → Slack: Send and Wait for Approval (message: {{ $json.preview }}) → IF approved → PostWire: Publish (Content: Drafts From a Previous Step, Drafts: {{ $('Write drafts').item.json.drafts }}).
Alert in Slack when a post fails or a login expires
PostWire Trigger (Events: Post Failed, Connection Needs Sign-In) → Slack: Send Message ({{ $json.data.platform }}: {{ $json.data.error || $json.data.reason }}).
Tell the client’s channel when their post is approved
PostWire Trigger (Events: Approval Decided, Options → Brand ID) → IF {{ $json.data.decision }} is approved → Microsoft Teams / Slack / Gmail.
Ready-to-import templates: n8n.io/creators/postwire.
Pricing
Priced per brand — one business with all of its networks — not per channel. Adding a fifth network to a brand never changes the bill. X is an add-on of the paid plans, billed in X credits.
| | Brands | Posts/month | |
|—|—|—|—|
| Free | 1 | 20 | no card |
| Starter | 3 | 300 | $9/mo |
| Pro | 10 | 2,000 | $29/mo |
| Agency | 50 | 15,000 | $99/mo |
| Scale | 200 | no monthly cap | $299/mo |
Current prices: postwire.io/pricing.
Compatibility
Tested with n8n 2.40. Workflows built with version 1 of the node (package 0.1.x–0.2.x) keep working unchanged; new nodes use version 2. Everything added in 0.4.0 is additive: a workflow saved with 0.3.x opens and runs as before (a Schedule without When uses Publish At).
Resources
License
MIT