curl --request POST \
--url https://api.indm.social/v1/automations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31",
"keywords": [
"GUIDE"
],
"dm_message": "Here's the spring planting guide. Enjoy it."
}
EOFconst options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
media_id: '3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31',
keywords: ['GUIDE'],
dm_message: 'Here\'s the spring planting guide. Enjoy it.'
})
};
fetch('https://api.indm.social/v1/automations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.indm.social/v1/automations"
payload = {
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31",
"keywords": ["GUIDE"],
"dm_message": "Here's the spring planting guide. Enjoy it."
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "9a4b1c7e-2d3f-4a5b-8c6d-1e2f3a4b5c6d",
"name": "Spring guide reel",
"status": "live",
"trigger": "comment",
"binding": "specific",
"account_id": "6f1c2a9e-3b7d-4e21-9a55-0c8d2f4b7e10",
"keywords": [
"GUIDE"
],
"dm_sent_count": 182,
"created_at": "2026-11-05T09:02:11Z",
"updated_at": "2026-11-05T09:04:30Z",
"dm_message": "Here's the spring planting guide. Enjoy it.",
"button_label": "Send me the guide",
"public_replies": [
"Sent it to your DMs."
],
"links": [
{
"url": "https://example.com/spring-guide",
"title": "Open the guide"
}
],
"opener_message": "",
"opener_plain_text": false,
"follow_gate": false,
"email_gate": false,
"follow_gate_message": "",
"follow_gate_visit_label": "",
"follow_gate_following_label": "",
"email_gate_message": "",
"followup_message": "",
"followup_delay_minutes": 0,
"caveats": [
{
"code": "followup_goes_to_everyone",
"message": "The follow-up goes to everyone who received the first message, including people who already tapped the link."
}
],
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31"
}Create an automation
Builds a comment-to-DM automation on one of your posts or reels. It is always
created as a draft, so nothing reaches anyone until you
set it live.
The post decides the workspace and the account, so media_id is the one id you
need. A post runs one live automation at a time; if another is already live on it,
the call is refused with 409 live_automation_on_media rather than leaving you a
draft that can never go live.
The response is the automation as saved, which is not always exactly as asked for.
caveats names anything that was adjusted. Read from the response, not from your
request.
Needs a full key.
curl --request POST \
--url https://api.indm.social/v1/automations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31",
"keywords": [
"GUIDE"
],
"dm_message": "Here's the spring planting guide. Enjoy it."
}
EOFconst options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
media_id: '3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31',
keywords: ['GUIDE'],
dm_message: 'Here\'s the spring planting guide. Enjoy it.'
})
};
fetch('https://api.indm.social/v1/automations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.indm.social/v1/automations"
payload = {
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31",
"keywords": ["GUIDE"],
"dm_message": "Here's the spring planting guide. Enjoy it."
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "9a4b1c7e-2d3f-4a5b-8c6d-1e2f3a4b5c6d",
"name": "Spring guide reel",
"status": "live",
"trigger": "comment",
"binding": "specific",
"account_id": "6f1c2a9e-3b7d-4e21-9a55-0c8d2f4b7e10",
"keywords": [
"GUIDE"
],
"dm_sent_count": 182,
"created_at": "2026-11-05T09:02:11Z",
"updated_at": "2026-11-05T09:04:30Z",
"dm_message": "Here's the spring planting guide. Enjoy it.",
"button_label": "Send me the guide",
"public_replies": [
"Sent it to your DMs."
],
"links": [
{
"url": "https://example.com/spring-guide",
"title": "Open the guide"
}
],
"opener_message": "",
"opener_plain_text": false,
"follow_gate": false,
"email_gate": false,
"follow_gate_message": "",
"follow_gate_visit_label": "",
"follow_gate_following_label": "",
"email_gate_message": "",
"followup_message": "",
"followup_delay_minutes": 0,
"caveats": [
{
"code": "followup_goes_to_everyone",
"message": "The follow-up goes to everyone who received the first message, including people who already tapped the link."
}
],
"media_id": "3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31"
}Authorizations
An API key from Settings → API keys in the inDM app, sent as
Authorization: Bearer indm_.... Keys belong to one workspace and carry a scope:
read for GET routes and the validate dry run, full for everything. Keep keys on
your server; never ship one to a browser or a mobile app.
Body
A new automation. media_id, keywords and dm_message are required.
The post or reel to attach it to, from List media.
"3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31"
The words that trigger it. Case-insensitive, so GUIDE also matches guide.
A keyword belongs to one automation. Up to 20.
1 - 20 elements["GUIDE"]
The direct message the fan receives, carrying the link. Write it in the language your audience reads; an automation sends in whatever language its copy is in. With an opener set, this becomes the second message. Up to 1,000 characters.
1000"Here's the spring planting guide. Enjoy it."
Optional. inDM takes the account from media_id, so you can leave this out.
A short name for your own list in inDM.
"Spring guide reel"
The opt-in button's label. Up to 20 characters.
20"Send me the guide"
A public reply posted under the fan's comment. Up to 2,200 characters.
2200"Sent it to your DMs."
The one link the DM delivers. Starts with https:// or http://. For more than
one link, use links instead.
"https://example.com/spring-guide"
The label on the link's button. Up to 20 characters.
20"Open the guide"
Two or three links, in the order the fan sees them, instead of link_url. One
message carries at most three links; that ceiling is Instagram's. How many a
workspace can attach depends on its plan.
3Show child attributes
Show child attributes
An opt-in message sent first. When set, dm_message becomes the second message
and the fan receives it only after they reply. You don't need an opener to
deliver a link: the one private reply a comment earns can carry the link on its
own. An opener makes the link follow a yes, and the fan's reply opens the 24-hour
window for anything sent after it. Up to 1,000 characters.
1000Send the opener as plain text with no button, so any reply counts as the
opt-in. Only meaningful with opener_message.
Ask the fan to follow the account before the link arrives. Needs a link. After four asks the link is delivered anyway.
Your own words for the follow ask, in place of inDM's. Needs follow_gate.
The label on the button that opens your profile. Up to 20 characters. Needs follow_gate.
20The label on the button a fan taps once they follow. Up to 20 characters. Needs follow_gate.
20Ask the fan for an email address before the link arrives. Needs a link.
Your own words for the email ask, in place of inDM's. Needs email_gate.
A second message sent later, to everyone who received the first one. It can't be
held back from people who already tapped the link. It needs something that opens
the 24-hour window first, so an opener_message, follow_gate or email_gate.
Whether it sends depends on the workspace's plan. Up to 1,000 characters.
1000How long after the first message the follow-up goes out, from 30 minutes to 20
hours (1,200 minutes). The ceiling is Instagram's 24-hour window minus headroom.
Required with followup_message.
30 <= x <= 1200Response
The automation, saved as a draft.
The automation as saved, and anything that was adjusted on the way in.
"9a4b1c7e-2d3f-4a5b-8c6d-1e2f3a4b5c6d"
"Spring guide reel"
draft, live, paused "live"
What fires it, such as comment.
"comment"
How it is attached to content: specific for one post, next for the next post
the account publishes, any for every post.
"specific"
"6f1c2a9e-3b7d-4e21-9a55-0c8d2f4b7e10"
The words that trigger it, as stored.
["GUIDE"]
DMs this automation has sent since it was created.
182
"2026-11-05T09:02:11Z"
"2026-11-05T09:04:30Z"
The message carrying the link. With an opener, this is the second message.
"Here's the spring planting guide. Enjoy it."
The opt-in button's label.
"Send me the guide"
The public replies inDM posts under a fan's comment, one per comment. Empty when there are none.
["Sent it to your DMs."]
The links the DM delivers, in the order the fan sees them. Empty when there are none.
Show child attributes
Show child attributes
The opt-in message sent first. Empty when there is no opener.
""
Whether the opener is sent as plain text with no button.
false
Whether the fan is asked to follow before the link arrives.
false
Whether the fan is asked for an email address before the link arrives.
false
Your own words for the follow ask. Empty when inDM's wording is used.
""
The label on the button that opens your profile. Empty for inDM's.
""
The label on the button a fan taps once they follow. Empty for inDM's.
""
Your own words for the email ask. Empty when inDM's wording is used.
""
The second message sent later. Empty when there is no follow-up.
""
How long after the first message the follow-up goes out. 0 when there is no follow-up.
0
Anything about the saved automation that differs from the request, or that is worth knowing before it goes live. Empty when there is nothing to add.
Show child attributes
Show child attributes
The post it is attached to. Present when binding is specific.
"3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31"