Shipping an Instagram DM automation engine without breaking Meta's rules: 6 lessons Targenix, a free automation platform for businesses in Uzbekistan selling through Facebook and Instagram ads, rebuilt its Instagram DM automation as a flow engine with 9 triggers, 17 step types, and an AI reply step, and documented six lessons from working within Meta's Instagram Messaging API and Messenger Platform rules. The team found that comment-triggered private replies must be sent before a run can be keyed to a recipient ID, that the 24-hour messaging window must be evaluated per send reason, and that inbound webhooks rather than timers must resume flows waiting on customer replies. They also validated the new engine against the old one in a 48-hour shadow mode, writing decisions to the database rather than stdout logs, and flagged Meta error 10903, which blocks private replies to users holding a page role. We run Targenix https://targenix.uz/en , a free automation platform for businesses in Uzbekistan that sell through Facebook and Instagram ads. This year we replaced our hard-coded "reply to a comment, then ask for a phone number" logic with a real flow engine: 9 triggers ad comment, DM, story reply, story mention, ad click, ig.me link, Ice Breakers, persistent menu, button , 17 step types, and an AI reply step for everything the flow does not cover. The engine itself was the easy part. The hard part was the platform rules and the edge cases they create. Here is what we would tell anyone building on the Instagram Messaging API and Messenger Platform. When someone comments under an ad, you are allowed to send them one private reply about that comment. It is addressed to the comment, not to the person. You do not know the customer's messaging ID PSID/IGSID until the Send API returns it in its response. That changes your data model. We had assumed "a conversation starts with a user id", so a run was keyed on the user before anything was sent. For comment flows that is impossible. The fix: send the private reply first, read the recipient id from the response, and only then open the run. Our first version applied the 24-hour check to the private reply as well. Every comment flow older than a day died on its first step, silently. If you model "can I send now?" as a single function, give it the reason you are sending, not just the timestamp. A flow often greets the customer and then waits for their answer. We implemented the wait as a state awaiting first inbound message and, out of habit, attached it to the scheduler that handles timed waits. A timer can never know that the customer replied. The result was a flow that said hello once and then stayed silent forever. The inbound webhook has to resume the run. Timers are only for "no answer after N hours". We did not switch engines at once. For every page in the pilot, the new engine processed each event and recorded what it would have sent, while the old code kept answering customers. We compared the two decisions for 48 hours, fixed the differences, then enabled real sending page by page. One practical detail: write the shadow decisions to the database, not to logs. Our logs went to stdout, and a deploy recreates the container. The first comparison window disappeared with it. A page cannot send a private reply to a person who has a role on that page. Meta returns error 10903 "This user can't reply to this activity" . The owner commenting on their own ad is the most natural test, and it never works. Keep a role-less test account for end-to-end checks, and do not read 10903 in production as "the engine is broken". A pure AI chat drifts. A pure rule-based flow breaks the moment the customer asks something unexpected "do you deliver to Samarkand?" . What worked for us: Each public comment reply is generated separately, so a hundred "price?" comments do not get a hundred identical answers. Repeated template text is what both users and platforms read as spam. No broadcasts, no "we miss you" messages days later, no messages to people who never wrote. Conversations start with the customer and stay inside the window. Keeping messaging permissions is worth more than any single campaign. If you are solving the same problem for a Facebook or Instagram business, Targenix does all of the above without code and is free one plan, 0 UZS, AI included : targenix.uz/en https://targenix.uz/en . Questions about the Messenger Platform edge cases are welcome in the comments.