Description
n8n-nodes-postora
This is an n8n community node for Postora — the AI-powered social media management platform.
Publish content to Instagram, Facebook, TikTok, YouTube, Twitter/X, LinkedIn, Pinterest, Threads, Bluesky, and Reddit directly from your n8n workflows.
n8n is a fair-code licensed workflow automation platform.
Installation
Follow the installation guide in the n8n community nodes documentation.
1. Go to Settings → Community Nodes
2. Click Install a community node
3. Enter n8n-nodes-postora
4. Click Install
Operations
Post
- Create — Publish content to one or more social media platforms
- Get Status — Check the publishing status of a post
- List — List recent posts with optional status filter
- Upload — Upload an image or video file to the Postora media library. Accepts three sources (see Media → Upload below):
- Get — Retrieve one uploaded media file by its UUID.
- Register — Register an HTTPS callback URL for Postora events. Leave events empty to receive the default event set.
- List — List registered webhook subscriptions.
- Test — Send a test event to a registered webhook subscription.
- Delete — Remove a webhook subscription.
Media
– Binary Property — a file from a previous n8n node
– URL — download from a public web address (http/https)
– Media File ID — look up & re-attach a file already in Postora (no re-upload)
Webhook
Postora Trigger
Starts a workflow when Postora sends a selected event. n8n registers and removes the callback automatically when the workflow is activated or deactivated.
Since v1.6.0 this is the only trigger node — it absorbed the former Postora Comment Trigger.
Since v1.7.0 it asks for the Event Category first (v1.8.0 dropped the separate Platform field):
| Property | Meaning |
|—|—|
| Event Category | Any mix of Post Completed, Message Received, Comment Received. Each category you pick adds its own platform selector below |
| Message Platforms | All Platforms (message.received), WhatsApp (message.whatsapp), Instagram (message.instagram), Facebook (message.facebook). Threads is not offered — Postora never emits a Threads direct message |
| Comment Platforms | All Platforms (comment.received), Facebook (comment.facebook), Instagram (comment.instagram), Threads (comment.threads). WhatsApp is not offered — it has no public comments |
| Account | Loaded from your connected accounts (GET /api/v1/accounts) and narrowed to the platforms your selection implies — pick WhatsApp under Message Received and only WhatsApp accounts are listed. “All accounts” applies no account filter. An account is on exactly one platform, so this is also the platform filter; post.completed carries no single account and is delivered regardless |
The subscription is the union of everything selected. Adding the node from n8n’s triggers side
panel pre-selects that one event; it is replaced the moment you pick a category.
Postora stores Platform and Account on the subscription and matches each event against them
server-side, so one trigger can serve one account on one platform or everything at once.
A Threads reply or mention arrives as comment.received with platform: "threads"; read
comment.kind to tell a reply from a mention. The legacy threads.mention.created /
threads.mention.replied events are no longer offered (v1.8.0) — a mention already arrives as
comment.threads, and “replied” only confirmed a reply sent from Postora’s own Mentions page.
Workflows that saved them keep receiving them. WhatsApp has no public comments and Threads has
no direct messages, so those pairings never fire.
The triggers side panel offers nine entries — Post Completed, DM Message (All / WhatsApp /
Facebook / Instagram), Comment (All / Facebook / Instagram), Reply / Mention (Threads); picking
one pre-selects that event until you choose a category.
Workflows saved on an earlier version keep their saved selection untouched — v1.6.0 nodes keep
their flat Events list, v1.5.0 nodes their categories without filters. Only newly added
Postora Trigger nodes get the current properties.
Every message.* event carries the same body, so one workflow can serve several connected accounts:
{
"event": "message.received",
"platform": "instagram",
"socialaccountid": "c32dd852-9f63-4bc0-a99a-eb951cb830bb",
"account": { "id": "c32dd852-…", "platform": "instagram", "name": "danatfuture", "username": "danatfuture", "handle": "@danatfuture" },
"conversation_id": "…",
"sender": { "id": "96555683677", "name": "Customer", "phone": "96555683677" },
"message": { "id": "…", "text": "Hello", "type": "text", "attachments": [] },
"timestamp": "2026-08-22T10:00:00.000Z"
}
account identifies which of your connected accounts received the message: name is the platform username (or the WhatsApp number when the platform reports no username) and handle is the @-prefixed username on Instagram/Facebook (null for WhatsApp). To reply into the same conversation, pass socialaccountid and sender.id to Message → Reply — the node’s defaults already do this — and the pair uniquely routes the reply back to the right account and thread, however many accounts are connected. The reply response echoes the same account object.
Since v1.4.1 the Message fields fall back to the trigger by name when $json is not the trigger’s
output, matching the Comment fields:
{{ $json.socialaccountid ?? $('Postora Trigger').first().json.socialaccountid }} and
{{ $json.sender?.id ?? $json.sender?.phone ?? $('Postora Trigger').first().json.sender.id }}.
Put an AI Agent between the trigger and the reply and $json is the agent’s output, which is how
these fields used to resolve to nothing. Social Account ID is also checked for UUID shape
before the request goes out, so pasting a Facebook page ID, an Instagram username or sender.id
now fails in the node with a message naming the mistake instead of returning a server error.
Social Account ID must belong to the same Postora account as the node’s API key. A UUID from a
different Postora user returns 404 ACCOUNTNOTFOUND — that check is the tenancy boundary and is
enforced server-side, so the node deliberately lets a valid-looking UUID through. If you run
workflows for more than one Postora tenant on one n8n instance, give each its own credential and
keep each reply node on the trigger that matches it. Run Account → List with a credential to
see the UUIDs it can send from.
Changing the event selection takes effect the next time the workflow is activated: on activation the node compares its selection against the subscription registered with Postora and re-registers when they differ. Before v1.2.1 the original subscription was kept regardless, so an edited selection was silently ignored — if you edited the selection on an already-active workflow under an older version, deactivate and reactivate it once after upgrading.
Comment
| Operation | Platforms | Endpoint |
|—|—|—|
| Reply | Facebook, Instagram, Threads | POST /api/v1/comments/reply |
| Hide | Facebook, Instagram, Threads | POST /api/v1/comments/hide (hide: true/false) |
| Delete | Facebook, Instagram | POST /api/v1/comments/delete |
Platform defaults to Auto-detect (added in v1.4.0), which leaves the platform out of the
request entirely: Postora already knows whether the Social Account ID you send belongs to a
Facebook, Instagram or Threads account, and derives the platform from it. That is why one Comment
node handles a Postora Trigger set to All platforms without a Switch in front of it. Picking a
platform explicitly is only useful as a safety check — the API then rejects the call with
platform does not match the selected social account when the account is not on that platform.
On Auto-detect the node reads the incoming platform field where it can, purely so a Delete
aimed at Threads fails immediately with “Use the Hide operation instead” rather than after a round
trip. When it cannot read one — an AI Agent in between with a renamed trigger, for instance — the
API’s own Threads guard still refuses the delete.
Since v1.5.0, when the platform resolves to Threads the node also checks the shape of **Comment
ID** before sending. Threads IDs are digits only (17875366935604207), so a Facebook comment ID
(postid_commentid) or left-over pinned test data now fails in the node naming the mistake,
instead of reaching Threads and coming back as
Param replytoid is not a valid threads_media ID.
The field defaults read a Postora Trigger payload, falling back to the trigger by
name when $json is not the trigger’s output:
{{ $json.socialaccountid ?? $('Postora Trigger').first().json.socialaccountid }}.
That fallback matters because $json is always the immediately preceding node’s output, not
the trigger’s. In a Postora Trigger → AI Agent → Comment Reply workflow the AI Agent sits in
between, so a bare {{ $json.socialaccountid }} resolves to nothing and the node fails with
Required parameter 'Social Account ID' is missing or empty — on a field that visibly contains
an expression.
Two things this does not cover, both of which need a manual edit:
trigger’s output panel and let n8n write the reference.
{{ $json.response }}, which matches a Code/HTTP node that returns a response field. n8n’s built-in AI Agent returns output, so point it at
{{ $json.output }} when the reply text comes from an AI Agent.
Defaults apply only when a node is first added — an existing node keeps whatever expressions were
saved with it, so upgrading the package does not rewrite a workflow you already built.
Account
Comment events
Prerequisite — the trigger receives nothing without it: in Postora, open the platform’s
Messaging page → Auto Replies → Automation, and set Comments to n8n for that
account. Registering the trigger alone does not start delivery.
Workflows built on the former Postora Comment Trigger (v1.3.0–v1.5.0) must be rebuilt on
Postora Trigger after updating: the old node type no longer exists in the package, so n8n
cannot activate a workflow that still contains it, and the subscription it registered stays
behind on Postora until you delete it there (DELETE /api/v1/webhooks/{id}) or the rebuilt
workflow is activated and deactivated once.
Threads needs nothing in the Meta App Dashboard. Postora polls the Threads API itself
(every two minutes) for new replies under your recent posts and for new mentions, and sends
each one as comment.received — Meta’s Threads Webhooks product has never reliably delivered
replies, and it has no mentions webhook field at all (threadsmanagementions only unlocks
a read). The poll starts on the first comment after the account’s Comments automation handler
is set to n8n; older comments are recorded but not replayed into your workflow.
Comments authored by the connected account itself are never delivered. Without that
suppression an auto-reply workflow would receive its own reply as a new comment and answer
itself in a loop.
Example payload:
{
"event": "comment.received",
"platform": "instagram",
"socialaccountid": "c32dd852-9f63-4bc0-a99a-eb951cb830bb",
"account": { "id": "c32dd852-…", "platform": "instagram", "name": "danatfuture", "username": "danatfuture", "handle": "@danatfuture" },
"comment": { "id": "17891234567890", "kind": "comment", "text": "Love this!", "parentcommentid": null, "media_url": null },
"post": { "id": "17845678901234", "url": null, "caption": null },
"author": { "id": "1234567890", "name": null, "username": "fan" },
"timestamp": "2026-08-22T10:00:00.000Z"
}
comment.kind distinguishes a top-level comment from a reply under another comment and,
on Threads, from a mention of your account. To answer, pass socialaccountid and
comment.id to Comment → Reply — the node’s defaults already do this.
Credentials
You need a Postora API key to use this node:
1. Sign up at postora.cloud
2. Go to Settings → API Keys
3. Generate a new API key
4. In n8n, create a new Postora API credential and paste the key
Usage Examples
Schedule a Post to Instagram
1. Add a Postora node to your workflow.
2. Set Resource to Post.
3. Set Operation to Create.
4. Set Platform to Instagram.
5. In Social Accounts, select the Instagram account(s) to publish to.
6. (Optional) Set Post Type to Reel for short-form video or Story for ephemeral content.
7. Write your Caption (disabled for Stories — only media is posted).
8. Set Media Source to URL and paste a direct image or video URL (e.g. https://example.com/photo.jpg).
9. (Optional) Set Schedule At to a future date/time to publish later. Leave empty to post immediately.
10. (Optional) Expand Additional Options and add a First Comment.
11. Execute the node. Since v1.1.13, immediate posts return their completed post record, including one entry per account in post.platformresults; use each posturl to open the published post. Scheduled posts return before publishing, so use Post → Get Status after the scheduled time to retrieve their URLs. If the status lookup fails after creation, the response includes poststatuslookup_error and retains the created post ID for a later status check.
For example, an immediate post can return:
{
"post": {
"id": "post-uuid",
"status": "completed",
"platform_results": [
{ "platform": "instagram", "status": "success", "post_url": "https://instagram.com/p/..." }
]
}
}
List Connected Accounts
Use this to verify your credentials work and discover which social accounts are available:
1. Add a Postora node to your workflow.
2. Set Resource to Account.
3. Set Operation to List.
4. Execute the node. The output lists every connected social account with its ID, name, and platform.
Publish a YouTube Video
1. Add a Postora node to your workflow.
2. Set Resource to Post.
3. Set Operation to Create.
4. Set Platform to YouTube.
5. In Social Accounts, select the YouTube channel to publish to.
6. Write your video description in Caption.
7. Set Media Source to URL and paste a direct video URL.
8. Expand Additional Options and configure:
– YouTube Title — the video title.
– YouTube Visibility — Public, Unlisted, or Private.
– YouTube Category — category ID (default: 22 for People & Blogs).
9. Execute the node.
Platform-Specific Options
When creating a post, you can set platform-specific options:
| Platform | Options |
|———-|———|
| YouTube | Title, Privacy (public/unlisted/private), Category ID |
| TikTok | Privacy level, Allow Comments/Duet/Stitch |
| Pinterest | Board ID, Title |
| Reddit | Subreddit, Title |
Media → Upload
The Media → Upload node ingests files into your Postora media library. Choose where the files come from with the Media Source dropdown. Every source produces the same output shape:
{ "total": 2, "uploaded": 2, "failed": 0, "results": [ { "success": true, ... }, { "success": true, ... } ] }
The results array contains one entry per input item. Each entry has success: true|false plus source-specific fields (field for binary, url for URL, file_id for Media File ID).
Source 1 — Binary Property (n8n file)
Default. Reads one or more binary properties produced by an upstream node and uploads each as a multipart file.
data. For multiple files, use comma-separated names: data,data1,data2.Source 2 — URL (download from web)
Downloads each URL on the n8n side and uploads the bytes to Postora. SSRF hardening: only http/https schemes; literal private/loopback/link-local/reserved IPs (IPv4 and IPv6) and well-known internal hostnames are rejected — checked on the original URL and on every redirect hop, before that hop is requested (up to 5 hops); 50 MB max; 30 s per-hop timeout; the response Content-Type must be image/ or video/.
> Known limit: this checks the hostname/IP as written in the URL, not where DNS actually resolves it. A domain an attacker controls that resolves to an internal address (DNS rebinding) is not caught. If you accept media URLs from untrusted sources, treat this as defense-in-depth, not a full guarantee.
={{ $json.urls }}
Each bad URL (private host, wrong content-type, oversized, dead link) becomes a per-item failure in results; the node never crashes.
Source 3 — Media File ID (look up & re-attach)
Resolves Postora media file UUID(s) you uploaded earlier and re-attaches them to this item — no re-upload. The node calls GET /api/v1/media/:id for each UUID, validates each is a well-formed UUID, and de-duplicates.
={{ $json.file_ids }}
> Note on uploaded counts for this source: “uploaded” means successfully resolved & attached media items, not files re-uploaded to storage.
Invalid UUIDs, IDs you don’t own, and missing IDs each become a per-item failure with a clear message. The node never crashes on bad input. If the API key is rejected (HTTP 401), the whole node fails — because auth is broken for everything.
Backward compatibility
Workflows saved before v1.1.7 used a single Binary Property field (binaryPropertyName). Those workflows keep working unchanged: the node detects the legacy field and defaults the Media Source to Binary Property automatically.
Media Source Options
When creating a post, you can attach media using one of four methods:
| Source | Description |
|——–|————-|
| None | Text-only post, no media attached |
| URL | Provide one or more comma-separated media URLs (e.g., https://example.com/photo1.jpg,https://example.com/photo2.jpg) |
| Binary Data | Attach binary file(s) from previous nodes. Specify property names as comma-separated values (e.g., data,data1,data2) to upload multiple files at once |
| Media File ID | Reuse file(s) already uploaded via Media → Upload, by ID |
Binary Data Details
To use binary data:
1. Connect a node that outputs binary data (e.g., HTTP Request, Read Binary File)
2. Select Binary Data as the Media Source
3. Enter the binary property name(s) — default is data
4. For multiple files, use comma-separated names: data,data1,data2
Binary files are automatically converted to base64 and sent via the media_base64 API parameter.
Media File ID Details
If you already uploaded file(s) with a Media → Upload step (e.g. earlier in the same workflow), you can post them without re-uploading:
1. Select Media File ID as the Media Source on the Post → Create node.
2. Enter the ID(s) returned by the Upload step in Media File ID(s).
3. For multiple files, separate IDs with a comma: id-1,id-2,id-3. Wrapping them in brackets ([id-1, id-2, id-3]) also works — the brackets are stripped automatically.
Troubleshooting
The trigger fired while I was testing, then stopped
Test workflow listens only while that editor tab is open. It registers a subscription
with Postora when you press it and deletes it again the moment the editor stops listening,
so events arrive during the test and nothing arrives afterwards. There is no error, because
from Postora’s side there is simply no subscriber any more.
Fix: Save the workflow and toggle it Active. To confirm it took, open
API Keys in Postora — the Webhook Subscriptions card lists everything currently
registered for your account. An empty card means nothing is listening.
The trigger never fires at all
Check the same Webhook Subscriptions card first, then Connection Health. Each
messaging account there shows its webhook identity — the id the platform actually uses
to address it — and when it last received an inbound event. An account reading *”Never
received an inbound event”* is usually not the account being messaged: Instagram in
particular issues several ids per account, and it is easy to connect one profile while
messaging another.
“Could not find any entity of type BinaryDataFile matching…”
This error comes from n8n itself, not from this node — it means n8n can no longer find the actual file bytes for a binary field on the item you’re processing.
The most common cause: the upstream node’s output was pinned (📌) in the n8n editor while you were building the workflow. Pinning freezes the shape of the data, but the underlying file content lives in n8n’s own storage and can be cleaned up over time (e.g. on restart, or by n8n’s execution data retention settings). Once that happens, the pinned item still looks like it has a file attached, but reading it fails with this error.
Fix: unpin the upstream node (click the pin icon again to remove it) and re-run the workflow with a fresh execution before testing Media → Upload or Post → Create with binary data.