Automations
Send a DM, a public reply or both when someone comments a keyword, replies to a story or mentions you, with follower rules, link tracking and repeat limits.
A comment automation watches one post (or every post on an account) for a keyword and answers each matching comment automatically: a private DM to the commenter, a public reply under the comment, or both. It is the classic "comment GUIDE and I'll send it to you" funnel, without a graph to build.
| Platform | What the automation does |
|---|---|
| DM (with buttons, quick replies, a product card or media), public reply, like or hide the comment, follower rules. Also story replies, story mentions and live comments | |
| DM, public reply, like or hide the comment | |
| TikTok, Threads, LinkedIn, YouTube | Public reply only. These platforms have no private reply to a comment |
X accounts are refused with 400 platform_not_supported.
#Create one
This automation answers anyone who comments "guide" under one reel with a DM and a button, then thanks them publicly.
curl -X POST https://api.pozy.ai/v1/comment-automations \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1e2a3b4c5d6e7f80911",
"accountId": "6650c1e2a3b4c5d6e7f80a22",
"name": "Guide giveaway",
"platformPostId": "17912345678901234",
"keywords": ["guide"],
"matchMode": "word",
"dmMessage": "Hey {{first_name}}! Here is the guide you asked for.",
"buttons": [{ "type": "url", "title": "Get the guide", "url": "https://acme.example/guide.pdf" }],
"commentReply": "Sent it to your DMs, {{first_name}}!",
"commentReplyVariations": ["Check your inbox!", "On its way to your DMs."],
"actions": { "likeComment": true }
}'const res = await fetch("https://api.pozy.ai/v1/comment-automations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
profileId: "6650c1e2a3b4c5d6e7f80911",
accountId: "6650c1e2a3b4c5d6e7f80a22",
name: "Guide giveaway",
platformPostId: "17912345678901234",
keywords: ["guide"],
matchMode: "word",
dmMessage: "Hey {{first_name}}! Here is the guide you asked for.",
buttons: [{ type: "url", title: "Get the guide", url: "https://acme.example/guide.pdf" }],
commentReply: "Sent it to your DMs, {{first_name}}!",
commentReplyVariations: ["Check your inbox!", "On its way to your DMs."],
actions: { likeComment: true },
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.automation.id);import os
import requests
resp = requests.post(
"https://api.pozy.ai/v1/comment-automations",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"profileId": "6650c1e2a3b4c5d6e7f80911",
"accountId": "6650c1e2a3b4c5d6e7f80a22",
"name": "Guide giveaway",
"platformPostId": "17912345678901234",
"keywords": ["guide"],
"matchMode": "word",
"dmMessage": "Hey {{first_name}}! Here is the guide you asked for.",
"buttons": [{"type": "url", "title": "Get the guide", "url": "https://acme.example/guide.pdf"}],
"commentReply": "Sent it to your DMs, {{first_name}}!",
"actions": {"likeComment": True},
},
timeout=30,
)
print(resp.json()["automation"]["id"])The automation is active as soon as it is created. Send isActive: false to create it paused, and PATCH /v1/comment-automations/{id} to change it later.
#Choose what triggers it
trigger |
Fires on | Notes |
|---|---|---|
comment (default) |
A keyword comment on a post or reel | Every platform |
live_comment |
A keyword comment during one of your Instagram live broadcasts | Answered with a private reply while live |
story_reply |
A keyword reply to your Instagram story | platformPostId is the story id; omit it for any story |
story_mention |
Someone mentions your Instagram account in their story | Mentions carry no text, so leave keywords empty |
Which post. Pass platformPostId for one live post, or leave it out to watch every post on the account. To prepare an automation for a post you have scheduled but not published, pass the Pozy postId instead: the automation waits and arms itself when the post goes live.
Which comments.
| Field | Effect |
|---|---|
keywords |
Words that trigger it. An empty list matches every comment |
matchMode |
contains (default) matches anywhere, even inside another word ("app" fires on "happy"). word matches whole words only. exact needs the whole comment to be the keyword |
excludeKeywords |
Comments containing one of these never trigger, even if a keyword matches |
typoTolerance |
With word mode, also fire on close misspellings: one typo for keywords of 4 to 7 letters, two from 8 letters |
alsoMatchInDms |
Also answer people who send the keyword as a DM instead of commenting it. Needs at least one keyword |
Use word mode for short keywords. contains with a short keyword fires on far more comments than you expect.
#What the commenter gets
| Field | Notes |
|---|---|
dmMessage |
Required on Instagram and Facebook. Up to 640 characters when it has buttons, about 1,000 otherwise. Rejected on reply-only platforms |
dmMessageVariations |
Up to 5 alternative texts. Each comment gets one at random, so repeat commenters do not see identical messages |
buttons |
1 to 3 url, postback or phone buttons (titles up to 20 characters, phone on Facebook only) |
template |
A product card or a carousel of up to 10 cards, sent instead of the button bubble. Instagram shows cards in the mobile app only |
quickReplies |
Up to 13 chips. Not with buttons or template. Chips do not render in the message requests folder, where a first DM to a stranger lands, so prefer buttons for first contact |
dmMedia |
An image, video, audio clip or file, sent as a second message |
commentReply, commentReplyVariations |
The public reply under the comment. Required on reply-only platforms |
Personalise any text with {{first_name}}, {{name}} and {{username}}. Missing values become an empty string, so write copy that still reads well without them.
Link tracking. URL buttons are wrapped in a tracked redirect by default, so you can count clicks in the logs. Add clickTag to tag every contact who clicks. Send linkTracking: false to keep links exactly as written.
Continue into a workflow. A postback button with payload pozy:workflow:<workflowId> starts that workflow on tap, skipping its keyword condition. The workflow must be active on the same account and profile. The DM alone does not start it; the person has to tap. See Workflows.
#Timing and the public reply
dmDelaySeconds(up to 86,400) waits before sending the DM. The comment is still matched and deduplicated the moment it arrives.commentReplyDelaySecondswaits before the public reply. The public reply never goes out before the DM.publicReplyPolicy:after_dm(default) posts the public reply only after a successful DM.alwaysposts it whatever happens to the DM.actions.likeCommentandactions.hideCommentlike or hide the matched comment. They never block the DM, and when one cannot run, the log says why. Liking on Instagram is in limited release; see Comments.
#Follower rules (Instagram)
audience limits who gets the DM:
| Field | Values |
|---|---|
followerStatus |
any (default), follower, non_follower |
minFollowerCount |
Skip commenters with fewer followers than this |
whenUnknown |
send (default), skip or verify |
tapToUnlock |
Send everyone a confirm button first, and the real DM when they tap. No follow check at all |
Instagram only reveals whether someone follows you after they have messaged your account, and commenting does not count. So for most first-time commenters the answer is unknown, and whenUnknown decides:
senddelivers the DM anyway, so no real customer is silently dropped.skipstays silent.verifysendsfollowGate.messagewith a confirm button. The tap is itself a message, which lets Pozy check the follow, then send the real DM orfollowGate.notFollowingMessage.
followGate sets the copy: message, buttonLabel, an optional profileButtonLabel that opens your profile, and notFollowingMessage.
Instagram allows a single private reply per comment, within 7 days. If it refuses your DM, for example because buttons, cards or media were sent to someone who does not follow you, that reply is spent. When in doubt, open with plain text or use the follow gate, then send buttons once the person answers.
#Repeat rules and pacing
| Field | Effect |
|---|---|
repeatPolicy.mode: "once" (default) |
One DM per person per automation, ever. On reply-only platforms, one public reply per person |
repeatPolicy.mode: "every_comment" |
Every new matching comment is eligible. One comment is still answered at most once |
repeatPolicy.cooldownHours |
With every_comment, skip a repeat to the same person within this many hours. Sending it with once is a 400 |
dedupeSameTextHours |
Skip the DM if this person already got the identical text from this account, from any automation, within this many hours |
Platforms watch for accounts that send the same message to many people in a burst. Variations, deduplication and a small dmDelaySeconds all make an automation look less like spam and keep the account in good standing.
#How comments are caught
Comments reach Pozy by webhook in real time. As a safety net, Pozy also reads the latest comments every 10 minutes (the bound post, or the 5 newest posts for an account-wide automation) and answers any the webhook missed. Each comment is answered at most once, whichever path sees it first.
On Threads, LinkedIn and YouTube, comments are read by that poll only, so replies follow within about 10 minutes on posts from the last day, and less often on older posts. TikTok comments arrive by webhook for business accounts.
#Check what happened
GET /v1/comment-automations/{id}/logs lists every comment that triggered the automation, with the send status and the commenter. Filter by status:
status |
Meaning |
|---|---|
sent |
DM delivered |
pending |
Waiting on a delay or a follow gate |
gated |
A follow-gate message was sent and is waiting for the tap |
skipped |
Suppressed by a repeat rule, dedupe or audience rule. error says which |
failed |
The platform refused. platformError has the code |
Each row also shows the public reply status, likeSkipped and hideSkipped reasons, and link clickCount.
#Errors
| Error | Cause | Fix |
|---|---|---|
400 missing_required_field |
No dmMessage on Instagram or Facebook |
Add it |
400 naming a DM field |
A DM field on a reply-only platform | Send commentReply only |
400 with cooldownHours |
cooldownHours with mode once |
Use every_comment |
400 platform_not_supported |
An X account | Not available on X |
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/comment-automations |
List comment-to-DM automations |
POST /v1/comment-automations |
Create comment-to-DM automation |
GET /v1/comment-automations/{automationId} |
Get automation details |
PATCH /v1/comment-automations/{automationId} |
Update automation settings |
DELETE /v1/comment-automations/{automationId} |
Delete automation |
GET /v1/comment-automations/{automationId}/logs |
List automation logs |