Skip to main content
Beta. The Automations API is in beta and we are actively collecting feedback. Endpoints, payloads, and limits may change as we iterate. Please send feedback and bug reports to support so we can prioritize the right improvements.
The Automations endpoints let you define rules that automatically react to incoming Instagram engagement. Each automation pairs one or more triggers (the event that fires the rule) with one or more actions (what happens when it fires). A single rule can listen for multiple triggers and dispatch multiple actions — fire a webhook into your analytics pipeline AND send a DM from the same engagement. The engine only reacts to engagement a user directs at you (a comment, story reply, DM, or reaction) — it never sends follow-triggered DMs, first-message DMs to strangers, or bulk outbound — and it inherits Ayrshare’s per-account rate limits, per-recipient deduplication, and idempotent webhook ingestion.
sent means Meta accepted the message, not that the recipient received it. Delivery is ultimately dictated by the recipient’s Instagram Message requests setting: if they don’t allow message requests from everyone, Meta returns a success response and silently drops the message, and this is invisible at every API layer. Even a delivered comment-triggered DM arrives as a message request the recipient must accept (unless a conversation already exists between the two accounts). See Automation DM Sent but Not Delivered for the full explanation.

How it works

1

Create an automation

POST /automations with the triggers and actions you want. The automation activates immediately.
2

An end user engages

Someone comments on your post, replies to your story, sends a DM, or reacts to a DM. Meta delivers the webhook to Ayrshare.
3

Ayrshare matches and dispatches

The engine looks up every rule matching the event, checks per-action deduplication and your daily DM cap, then runs each action. A 20–60 second jitter is applied to DM sends to stay inside Instagram’s anti-spam heuristics.
4

Inspect what fired

GET /automations/:id/activity returns the audit log — every dispatch attempt, the per-action results, and any errors.

Triggers

You can attach up to 50 triggers to one automation. Each trigger is a discriminated union on the type field; type-specific fields live at the same level. All triggers are Instagram-only in v1. Keyword matching is case-insensitive and whole-word. An event satisfies a keyword-filtered trigger if it contains any one of the configured keywords. Omit storyId on a story trigger to fire on every story for the connected account.

Actions

You can attach up to 50 actions to one automation. They run sequentially; each result is recorded on the activity row.

Per-action dedup window

Every action — regardless of type — additionally accepts an optional top-level dedupWindowMinutes field that overrides the default 7-day per-recipient dedup window for that action only.
  • Set to 0 to disable dedup entirely for that action (typical for fire_webhook / send_email where the receiver expects every event).
  • Capped at 525600 (one year).
Action with a 24h dedup override

fire_webhook payload

When fire_webhook runs it POSTs a JSON body to your account-level webhook URL:
recipientUsername and keyword are null when the trigger doesn’t populate them (e.g. dm_keyword doesn’t carry a username on Meta’s payload; story_reply doesn’t have a keyword).

Template variables

send_dm.message, send_email.subject, and send_email.message support {{placeholder}} substitution. Unknown placeholders are rejected at create/update time (as a 473 validation error) so a typo never silently leaks the literal {{foo}} into a customer-facing message.
No sender_email / recipient_email. These are deliberately not exposed — your billing email has no legitimate place in a DM to a stranger, and Meta does not provide the recipient’s email on any IG webhook. Avoiding the placeholders prevents accidental disclosure.
Example template:

Rate limits and caps

The active-automation cap is counted per User Profile, not per parent account. Each profile under your account gets its own Business 10 / Enterprise 50, so an account with many profiles can run that many automations on each. It counts active automations and is enforced on both POST (create) and PUT re-activation (active: false → true), each surfacing error code 470. Need a higher per-profile limit? Contact support to have it raised for your account. The daily DM cap applies per parent Ayrshare account, shared across all your profiles, with a per-profile sub-cap so one busy profile cannot drain the whole account’s quota. When a DM cap is hit, the activity row records status rate_limited and no DM is sent. Structural caps on a single automation: 1–50 triggers, 1–50 actions. Instagram itself caps DMs at roughly 200/hour per account. The engine paces dispatch with a 20–60 second jitter to stay safely under this.

Activity statuses

A row in GET /automations/:id/activity carries a top-level status plus a per-action status inside actionResults[]: pending and in_flight are transient; everything else is terminal. When an automation has more than one action, the top-level status is derived from the per-action results in this order: auth_error if any action hit an auth error, then sent if any action was accepted, then deduplicated if every action was deduplicated, then skipped if every action was deliberately suppressed (skipped or deduplicated), otherwise failed. Read actionResults[] for the per-action detail.
sent is a platform-acceptance receipt, not a delivery receipt. Instagram does not expose message delivery to any API. A send_dm action is marked sent the moment Instagram accepts the message; whether the recipient actually receives it depends on their Instagram Message requests setting, which Ayrshare cannot read or influence. See Automation DM Sent but Not Delivered.

Error codes

The API returns two shapes of error:
  • Business-rule errors carry a numbered automation code (e.g. { "action": "automation", "code": 469, ... }).
  • Validation errors — any malformed request body (missing or invalid fields, unknown template variables, unrecognized keys) — are returned as a single 473 response with a details object that lists the offending fields. details is the validator’s output (formErrors plus fieldErrors). Branch on details, not on a per-condition code. In fieldErrors, keys are the top-level request fields (triggers, actions): a problem inside a specific entry, such as a trigger missing its keywords, is reported under that field (e.g. triggers), while formErrors holds object-level issues such as unrecognized keys.

What Meta does NOT allow

A few commonly-requested capabilities are not supported because Meta doesn’t permit them on the public Instagram API:
  • Auto-DM on new followers. Instagram does not publish a follow webhook.
  • First-message DMs to strangers. Meta requires the recipient to have engaged first (comment, reply, DM, reaction) before a business account can message them. Every supported trigger is anchored to such an engagement — but note that being allowed to send is not the same as the message being delivered: the recipient’s Instagram Message requests setting can still cause Meta to accept and then silently drop the message (see Automation DM Sent but Not Delivered).
  • Bulk outbound campaigns. Hourly DM caps and anti-abuse heuristics apply at the platform level.

Multi-profile usage

The endpoints respect the profileKey header. Pass a child profile’s key and the automation is created/managed under that profile. Rate limits split across profiles via a per-profile sub-cap so one chatty profile doesn’t drain the parent account’s quota.

FAQ

No. Instagram does not publish a follow webhook, and Meta does not allow third-party apps to send a DM to a user who has not engaged first. Every supported trigger (comment_keyword, story_reply, dm_reaction, dm_keyword) is anchored to such an engagement, which is what makes the send permissible.
sent means Instagram accepted the message, not that it was delivered. Delivery depends on the recipient’s Instagram Message requests setting — if they don’t allow message requests from everyone, Meta returns a success response and silently drops the message, with no error, webhook, or other signal on any API surface. A successful comment-triggered DM also arrives as a message request the recipient must accept (unless a conversation already exists). This is a permanent Instagram platform limitation. See Automation DM Sent but Not Delivered.
If the account’s Instagram credentials or messaging permissions genuinely fail — for example an expired or revoked access token, a missing Facebook Page selection, or Messaging not activated for the profile — the activity row records status auth_error and the DM is not retried. Resolving the account state (relinking, selecting a Page, or activating Messaging) lets the next matching engagement fire normally. This only applies to genuine credential and permission failures: if a specific DM could not be delivered for another reason — for example the recipient could not be found, or the triggering engagement came from the account that would send the DM — the row is recorded as failed or skipped with the reason on actionResults[].errorDetails, and relinking will not change the outcome.
Each send_dm dispatch is scheduled 20–60 seconds after the engagement to look organic to Instagram’s anti-spam systems. fire_webhook and send_email actions do NOT have jitter. The activity row’s created timestamp is when the trigger matched; completedAt is when dispatch finished.
Activity rows are retained indefinitely for trace and analytics. The GET /automations/:id/activity endpoint returns rows from the last 30 days for performance. (The dedup guard uses its own per-action window — defaulting to 7 days — which is unrelated to the activity lookback.)
No. Delete is a soft-delete: the master row is flagged deleted, no new dispatches occur, but historical activity rows remain readable via the activity endpoint.

Endpoints