Someone comments “guide” on your Instagram post. You want to send the guide privately, without asking them to find another link or waiting for someone to copy and paste a reply. The same pattern works for a Facebook Page: a specific comment triggers a specific, requested message.
The happy path is short. The important work is deciding which comments qualify, protecting the webhook, and preventing duplicate sends when events arrive more than once. This tutorial builds that bounded workflow in n8n using Outstand's comment webhooks and conversations API.
Download the importable n8n workflow and keep its setup README open. The JSON contains no secrets and imports inactive. It requires configuration, a verified webhook gateway and PostgreSQL before use. Local import and node checks are not a claim of live Instagram or Facebook delivery.
What the workflow does
The sequence is:
- Receive a signed Outstand event through your verification gateway.
- Accept only an allowlisted account and post on Instagram or Facebook.
- Match a whole-word keyword in a top-level, non-live comment.
- Atomically claim that comment in PostgreSQL.
- Acknowledge the webhook, then attempt one private reply.
- Record
sent,pending, orneeds_reviewfor follow-up.
The template deliberately does not send a public “check your DMs” comment. It also does not use a green n8n execution as evidence that the recipient received anything. Those distinctions matter when a request times out or the API returns a pending message.
Start with the right accounts and permissions
You need n8n, a persistent PostgreSQL database, an Outstand API key with conversations:send permission, and the connected Instagram professional account or Facebook Page that owns the target post. For Facebook private replies, the Page connection needs pages_messaging.
Outstand supports initiating these conversations as private replies to comments. Instagram requires the comment ID and its author's ID. Facebook requires the comment ID. In both cases, the connected account sends the message to the commenter; you do not supply an arbitrary recipient address.
There is a platform boundary: one private reply per comment, within seven days. Sending it does not open an unlimited follow-up sequence. Further messaging requires the person to reply and remains subject to the messaging window. Make the post's promise clear and send the resource the commenter actually requested.
Put signature verification before n8n
Subscribe to Outstand's comment.received event and configure the subscription URL as an HTTPS gateway you control. Do not point it straight at this template's webhook.
The gateway must verify X-Outstand-Signature against the exact raw request bytes using the Outstand webhook endpoint secret. The expected signature is sha256= followed by the hexadecimal HMAC-SHA256 digest. Reject missing or invalid signatures with a constant-time comparison before processing the event. Parsing and reserializing JSON before verification can change the signed bytes.
After verification, forward the event to n8n's production webhook URL using a separate random X-Verified-Gateway secret. Strip any incoming header with that name before inserting your own. Configure n8n's Webhook Header Auth credential to require it. A caller claiming to be “verified” is not a substitute for checking the signature.
This gateway is an explicit prerequisite, not something hidden inside the download. Apply payload limits, protect its secrets, and restrict direct access to the forwarding endpoint where possible. Have it acknowledge Outstand only after n8n responds. If n8n fails before acknowledgement, bounded event redelivery is safe because of the ledger; that is different from retrying a DM send.
Import and scope your campaign
Import the JSON in n8n and open Scope and build payload. Its CONFIG object holds only non-secret campaign settings: organization ID, keyword, reply content, and an allowlist of network/account/post combinations. The replacement defaults intentionally send nothing.
Copy IDs from a genuine verified comment event. accountId is the Outstand social account ID. platformPostId is the native platform post ID and is the field this template checks. Do not substitute Outstand's postId: posts published outside Outstand can have a null postId while still having a native platform ID.
The filter accepts only instagram or facebook, the configured organization, and an exact allowlisted account/post pair. It ignores replies to comments, live comments, unrelated events, missing identifiers and absent Instagram author IDs. This keeps a “guide” campaign from responding on every post your organization owns.
Keyword matching normalizes Unicode and compares lowercase whole tokens. GUIDE! matches guide; guidebook does not. This is intentionally not fuzzy matching or a multiword phrase engine. Change the filter deliberately if your campaign needs another matching rule, and retest it before activation.
Use the correct private-reply payload
The Send private reply node calls POST https://api.outstand.so/v1/conversations. Select a separate Header Auth credential with Authorization as the name and Bearer YOUR_OUTSTAND_API_KEY as the value. Keep the real key in n8n credentials, not in Code nodes or exported JSON.
For Instagram, the template builds:
1{
2 "social_account_id": "account-id",
3 "content": "Here is the guide you requested: https://example.com/guide",
4 "instagram": {
5 "comment_id": "comment-id",
6 "author_id": "author-id"
7 }
8}For Facebook, it builds:
1{
2 "social_account_id": "account-id",
3 "content": "Here is the guide you requested: https://example.com/guide",
4 "facebook": {
5 "comment_id": "comment-id"
6 }
7}These are platform-specific alternatives, not two sends for one event. Replace the example resource URL with your real destination before publishing.
Make duplicate prevention durable
Run the ledger creation SQL from the companion README in your own PostgreSQL schema. Select the same database credential on both Postgres nodes. Do not modify n8n's internal database tables.
The claim node inserts a key containing organization, network, account and comment into a table with a primary-key constraint. INSERT ... ON CONFLICT DO NOTHING makes the claim atomic. Two simultaneous executions cannot both claim the same key, unlike a “look up, then insert” sequence.
n8n responds with HTTP 202 only after that database step. A new claim continues to the send node; a duplicate or ignored event does not. The acknowledgement means the request has been handled at this boundary, not that a message was delivered.
Keep the ledger on persistent storage and back it up. Do not delete rows casually: removing a key removes its replay protection. The key is campaign-independent, so changing a keyword or message does not authorize another automatic attempt against the same comment.
This is not an exactly-once transaction across PostgreSQL and Outstand. If n8n crashes after claiming but before sending, the automatic message may never be sent. If it crashes after sending but before recording the result, the ledger can remain claimed. The template prioritizes avoiding duplicate messages over guaranteed automatic delivery.
Bound failures instead of blindly retrying
The HTTP node has a 15-second timeout, redirects disabled and automatic retries disabled. It captures response status and body, and routes transport failures into classification. A timeout is ambiguous: Outstand may have accepted the request even though n8n never received the response.
The classifier requires a successful response with conversation and message IDs. A message marked sent records sent; a message marked pending records pending. Rejections, unexpected responses and transport failures become needs_review. That includes rate limits and server errors: the workflow does not guess whether another send is safe.
Saved n8n execution progress helps investigation, but is not a recovery guarantee. Monitor needs_review, stale claimed, and stale pending rows using the README query. Configure an Error Workflow for executions that fail outright, plus separate ledger monitoring for handled errors that finish successfully. Apply execution pruning and access controls because payloads can contain personal data.
Before any manual resend, reconcile the ledger with Outstand's conversation/message records and delivery events. Never retry only the HTTP node or delete a claim to force a replay. If you later add public confirmation, trigger it only after verified sent delivery, including a correlated message.sent event for pending messages, with separate confirmation deduplication.
Test before activating
First test invalid gateway authentication, non-keyword comments, unsupported networks, wrong posts and missing Instagram authors. Then submit the same qualifying event twice and concurrently: only one claim should be admitted. Exercise sent, pending, rejected and timeout responses without messaging real recipients.
The downloadable workflow was imported and exported with n8n 2.47.5, with additional node and database checks documented in its README. Those checks do not validate your Meta permissions or production gateway. Finish with a controlled live test on your own connected account and a consenting commenter before expanding the campaign.
For the API rules behind the workflow, see Outstand's comment-to-DM guide, starting a conversation, and webhooks. Keep the automation narrow: one clear request, one scoped comment, one carefully tracked private reply.