InstantDM API Documentation
InstantDM is an Official Meta Business Partner that helps creators, businesses, and agencies automate their Instagram and Facebook DM conversations, comment responses, and lead generation flows. Built on the Meta Graph API.
What you can automate
Comment Automation — Automatically reply to comments and send DMs when someone comments on your post with a trigger word.
Flow Automation — Build multi-step DM flows with questions, buttons, media, and conditional logic. Collect leads, qualify prospects, and deliver content automatically.
AI Replies — Use AI models to generate contextual replies in DM conversations.
Why use the API?
The API lets you connect InstantDM with your existing tools. Receive real-time webhook events when comments, DMs, or flow completions happen. Send messages and reply to comments programmatically from Make.com, Zapier, n8n, or your own backend.
Platform
Official Meta Business Partner Built on Meta Graph API v25.0
Base URL
https://api.instantdm.com
Dashboard
https://app.instantdm.com
API Endpoint
POST https://api.instantdm.com/api-webhook
Webhook Config
Settings → Integrations → Webhook Configuration
API Keys
Settings → Integrations → API Keys
Authentication
All API requests require an API key. Generate one from your InstantDM dashboard under Settings → Integrations → API Keys.
Include the key in one of these headers:
| Header | Format |
|---|---|
Authorization | Bearer YOUR_API_KEY |
x-api-key | YOUR_API_KEY |
Example Request
curl -X POST https://api.instantdm.com/api-webhook \
-H "Authorization: Bearer sk-abc123..." \
-H "Content-Type: application/json" \
-d '{
"action": "send_message",
"type": "dm",
"recipient_id": "2358708294634624",
"message": {"text": "Hello!"}
}' Outbound Webhooks
InstantDM sends HTTP POST requests to your configured URL when events occur. Webhooks are dispatched asynchronously via SQS — they do not block the main DM processing pipeline.
Configure from: Settings → Integrations → Webhook Configuration
Headers on every webhook
| Header | Description |
|---|---|
Content-Type | application/json |
X-Event-Type | Event name (e.g. comment, dm_received) |
X-Timestamp | ISO-8601 UTC timestamp |
X-Webhook-Signature | HMAC-SHA256 hex digest (if secret configured) |
Available events
| Event | Trigger |
|---|---|
comment | New comment on a post with active automation |
dm_received | New inbound DM received |
postback | Button clicked in DM automation |
question_answered | User answers a flow question |
flow_completed | All nodes in a flow completed |
Delivery behavior
| Behavior | Detail |
|---|---|
| Timeout | 10 seconds |
| Retries | None — fire-and-forget |
| Batching | None — each event is a separate POST |
| Ordering | Not guaranteed |
| Duplicates | Possible (SQS at-least-once). Use mid or comment id for dedup. |
Error handling
Your endpoint should return a 2xx status code. Non-2xx responses are logged but never retried.
| Error Type | Behavior |
|---|---|
| HTTP 4xx/5xx | Logged, no retry |
| Timeout (10s) | Logged, no retry |
| Connection error | Logged, no retry |
Webhook delivery format
POST https://your-webhook-url.com Content-Type: application/json X-Event-Type: comment X-Timestamp: 2026-04-29T15:32:06+00:00 X-Webhook-Signature: a1b2c3d4...
Payload types
comment, dm_received, postback
→ Raw Instagram webhook payloads
(same structure Meta sends)
question_answered, flow_completed
→ InstantDM-specific structured data comment
Fired when someone comments on a post that has an active automation. This is a pre-processing webhook — it fires before the automation processes the comment.
The payload is the raw Instagram webhook event as received from Meta.
| Field | Description |
|---|---|
entry[].changes[].value.from | Who commented (id + username) |
entry[].changes[].value.text | Comment text |
entry[].changes[].value.media | Which post/reel was commented on |
entry[].changes[].value.media.media_product_type | Media type (e.g. REELS) |
entry[].changes[].value.id | Comment ID |
entry[].changes[].value.sender_id | Commenter's IG user ID |
entry[].changes[].value.recipient_id | Your IG account ID |
Example payload
{
"entry": [{
"id": "17841435672868203",
"time": 1778223729,
"changes": [{
"value": {
"from": {
"id": "27021621630806157",
"username": "pvamsi.krishna.73"
},
"media": {
"id": "17933258556187263",
"media_product_type": "REELS"
},
"id": "18114716611826474",
"text": "2013",
"recipient_id": "17841435672868203",
"sender_id": "27021621630806157"
},
"field": "comments"
}],
"object": "instagram"
}]
} dm_received
Fired when someone sends a DM to your account (outside of automation-initiated conversations). The payload is the raw Instagram webhook event.
| Field | Description |
|---|---|
entry[].messaging[].sender.id | Who sent the DM |
entry[].messaging[].message.text | Message text |
entry[].messaging[].message.mid | Message ID (use for deduplication) |
entry[].id | Your IG account ID (recipient) |
entry[].messaging[].timestamp | Message timestamp (ms) |
Example payload
{
"object": "instagram",
"entry": [{
"time": 1778223729706,
"id": "17841476961942794",
"messaging": [{
"sender": {
"id": "978239761327698"
},
"recipient": {
"id": "17841476961942794"
},
"timestamp": 1778223722476,
"message": {
"mid": "aWdfZAG1faXRlbToxOklHTWVz...",
"text": "New"
}
}]
}]
} postback
Fired when a user clicks a postback button in a DM automation (e.g., "Started following you!", "Get my content"). Fires before the automation processes the postback.
| Field | Description |
|---|---|
entry[].messaging[].postback.title | Button text the user clicked |
entry[].messaging[].postback.payload | JSON string with automation context (see below) |
entry[].messaging[].postback.mid | Message ID |
entry[].messaging[].sender.id | Who clicked the button |
Payload JSON fields
| Field | Description |
|---|---|
from.username | Who clicked |
media.id | Which post triggered the automation |
text | Original comment text |
user_id | InstantDM user who owns the automation |
creator_username | IG account that received the comment |
comment_reply | Whether this is a comment-triggered flow |
story_reply | Whether this is a story-triggered flow |
dm_reply | Whether this is a DM-triggered flow |
Example payload
{
"object": "instagram",
"entry": [{
"time": 1778223725146,
"id": "17841408795204378",
"messaging": [{
"sender": {
"id": "2031528510825908"
},
"recipient": {
"id": "17841408795204378"
},
"timestamp": 1778223723887,
"postback": {
"title": "Started following you! 👍",
"payload": "{\"from\": {\"id\": \"2031528510825908\", \"username\": \"__zain_z\"}, \"media\": {\"id\": \"17939513463036158\", \"media_product_type\": \"REELS\"}, \"text\": \"prompt\", \"recipient_id\": \"17841408795204378\", \"sender_id\": \"2031528510825908\", \"user_id\": \"e10b1fc8-cade-4608-99cd-ce269bee2a2b\", \"creator_username\": \"dr_amina_nijas\", \"comment_reply\": true, \"story_reply\": false, \"dm_reply\": false}",
"mid": "aWdfZAG1faXRlbToxOklHTWVz..."
}
}]
}]
} question_answered
Fired each time a user answers a question node in a flow automation. Gives you real-time data as the flow progresses. This is an InstantDM-specific structured payload (not a raw Instagram event).
| Field | Type | Description |
|---|---|---|
flow_id | string | Flow automation ID |
sender_id | string | Instagram user ID of the responder |
sender_username | string | Instagram username of the responder |
question | string | The question text that was asked |
question_type | string | Type: text, number, email, phone, address, etc. |
custom_variable_name | string | Variable name assigned to this answer |
user_response | string | The user's actual answer |
skip | boolean | true if the user skipped this question |
attempt_no | string | Flow attempt number |
timestamp | string | When the answer was recorded |
Example payload
{
"flow_id": "5a0441b5-6589-4452-b8bf-90902c865893",
"sender_id": "2031528510825908",
"sender_username": "__zain_z",
"question": "What's your name?",
"question_type": "text",
"custom_variable_name": "user_name",
"user_response": "Zain",
"skip": false,
"attempt_no": "1",
"timestamp": "2026-05-06 04:45:30.123456"
} flow_completed
Fired once when a user completes all nodes in a flow automation. Contains all collected data in one payload. This is an InstantDM-specific structured payload.
| Field | Type | Description |
|---|---|---|
flow_id | string | Flow automation ID |
flow_name | string | Name of the flow |
sender_id | string | Instagram user ID who completed the flow |
sender_username | string | Instagram username |
completed_at | string | Completion timestamp |
attempt_no | string | Flow attempt number |
tags | array | Tags assigned during the flow |
response_variables | object | Flat dict of variable_name → user_answer (easy to map in Make.com or Zapier) |
question_responses | array | Full array of all Q&A pairs in the flow |
Example payload
{
"flow_id": "5a0441b5-6589-4452-b8bf-90902c865893",
"flow_name": "Lead Capture Flow",
"sender_id": "2031528510825908",
"sender_username": "__zain_z",
"completed_at": "2026-05-06 04:46:15.654321",
"attempt_no": "1",
"tags": ["hot-lead", "interested"],
"response_variables": {
"user_name": "Zain",
"email": "zain@example.com",
"interest": "pricing"
},
"question_responses": [
{
"question": "What's your name?",
"question_type": "text",
"custom_variable_name": "user_name",
"user_response": "Zain",
"skip": false
},
{
"question": "What's your email?",
"question_type": "email",
"custom_variable_name": "email",
"user_response": "zain@example.com",
"skip": false
}
]
} Signature Verification
If you configure a webhook_secret, every outbound request includes an X-Webhook-Signature header with an HMAC-SHA256 hex digest.
The signature is computed as:
HMAC-SHA256(webhook_secret, raw_request_body)
Always verify the signature before processing the webhook to ensure it came from InstantDM. Use the raw request body (not parsed JSON) for verification.
hmac.compare_digest or crypto.timingSafeEqual) to prevent timing attacks.Node.js
const crypto = require('crypto');
function verify(rawBody, signature, secret) {
const computed = crypto
.createHmac('sha256', secret)
.update(rawBody) // use raw body, not parsed
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(computed),
Buffer.from(signature)
);
} Python
import hmac, hashlib
def verify(raw_body, signature, secret):
computed = hmac.new(
secret.encode("utf-8"),
raw_body.encode("utf-8"),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed, signature) Webhook Plan Eligibility
Webhooks are only delivered when the InstantDM account owner has an eligible paid plan.
| Plan | Webhook Limit |
|---|---|
| Trendsetter Pro (monthly/yearly) | 20,000 webhooks/hour |
| Multi Starter (monthly/yearly) | Credit-based |
| Multi Pro (monthly/yearly) | Credit-based |
| Multi Ultra (monthly/yearly) | Credit-based |
| Legacy plans (428337, 428338) | 2,000 webhooks/hour |
Inbound API
Call InstantDM's API to perform actions from external systems. All actions use a single endpoint.
POST https://api.instantdm.com/api-webhook
Required headers
| Header | Value |
|---|---|
Authorization | Bearer YOUR_API_KEY |
Content-Type | application/json |
Available actions
post_comment — Reply to a comment send_message — Send a DM or comment private reply
Reply to Comment
Reply to a specific Instagram comment publicly.
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | "post_comment" |
comment_id | string | Yes | Instagram comment ID |
comment_text | string | Yes | Reply text |
Request
{
"action": "post_comment",
"comment_id": "17890012345",
"comment_text": "Thanks! Check your DM"
} Response
{
"message": "Comment reply posted",
"comment_id": "17890012346"
} Send Message
Send a message via Instagram DM. Two types:
DM Message — Send to a user by their Instagram user ID.
Comment Private Reply — Reply to a comment privately via DM.
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | "send_message" |
type | string | No | "dm" (default) or "comment_reply" |
recipient_id | string | For dm | Instagram user ID |
comment_id | string | For comment_reply | Instagram comment ID |
message | object | Yes | Message content (see formats) |
DM Message
{
"action": "send_message",
"type": "dm",
"recipient_id": "2358708294634624",
"message": {"text": "Hello!"}
} Comment Private Reply
{
"action": "send_message",
"type": "comment_reply",
"comment_id": "17890012345",
"message": {"text": "Here's the link..."}
} Message Formats
The message field supports multiple formats. Pass the object directly — InstantDM forwards it to the Instagram Graph API.
For media support details and limitations, see the Meta Instagram Messaging API documentation.
Text
{"text": "Hello!"} Image
{"attachment": {"type": "image",
"payload": {"url": "https://example.com/photo.jpg"}}} Video
{"attachment": {"type": "video",
"payload": {"url": "https://example.com/video.mp4"}}} Audio
{"attachment": {"type": "audio",
"payload": {"url": "https://example.com/audio.mp3"}}} Button Template
{"attachment": {"type": "template",
"payload": {
"template_type": "button",
"text": "Choose an option:",
"buttons": [
{"type": "web_url", "title": "Visit", "url": "https://..."},
{"type": "web_url", "title": "More", "url": "https://..."}
]
}
}} Quick Replies
{"text": "Pick one:",
"quick_replies": [
{"content_type": "text", "title": "A", "payload": "A"},
{"content_type": "text", "title": "B", "payload": "B"}
]
} Rate Limits
API rate limits are based on your InstantDM plan. On top of that, Meta's own rate limits also apply. Whichever limit is reached first, the automation will be stopped.
If you hit a rate limit, messages are not retried automatically — you'll need to resend them in the next rate limit window.
Error Codes
| Code | Message | Cause |
|---|---|---|
| 401 | Missing API key | No Authorization or x-api-key header |
| 401 | Invalid API key | Key not found or revoked |
| 400 | Missing comment_id or comment_text | post_comment missing required fields |
| 400 | Missing recipient_id | send_message (dm) missing recipient |
| 400 | Missing comment_id for comment_reply | send_message (comment_reply) missing comment ID |
| 400 | Missing message | No message content provided |
| 400 | Unknown action | Invalid action value |
| 404 | No Instagram access token found | User has no connected IG account |
| 4xx/5xx | Instagram API error | Error passed through from Meta Graph API |
| 403 | API access requires higher plan | User's plan doesn't include API access |
| 403 | API & Webhook integrations require higher plan | Trying to enable webhook config on ineligible plan |
| 403 | API keys require higher plan | Trying to generate API key on ineligible plan |
| 429 | Hourly rate limit reached. Please try again later. | Trendsetter/Trendsetter Pro user hit their hourly limit (2,000/hr or 20,000/hr) |
| 402 | Insufficient credits. Please upgrade or purchase top-up credits. | Multi-account plan user ran out of credits |