Skip to main content
When a request doesn’t go through, you get an HTTP status and a body with one shape:
Every response, error or not, carries an X-Request-Id header. Include it when you write to support@indm.social and we can find the request at once.
New codes can appear within v1 as the API grows. If you meet a code you don’t recognise, fall back to its type: that tells you the status and the right response.

Types at a glance

invalid_request (400)

The request can’t be processed as sent. Retrying it unchanged gets the same answer.
Validate an automation answers 200 and lists what it finds under problems, using these same codes. A few codes only ever appear there, because they describe copy that would work badly rather than a request inDM can’t save: keyword_has_space, keyword_too_long and dm_promises_missing_link.

invalid_json

The body isn’t valid JSON, or a field has the wrong type, such as keywords sent as a string instead of an array. Check the body against the endpoint’s reference page.

method_not_allowed

The path exists, but not for this HTTP method, such as DELETE /automations/{automation_id}. This one answers 405 rather than 400. Each endpoint’s reference page shows its method.

media_id_required

Create an automation needs a media_id, the post or reel to attach it to. Get one from List media.

automation_id_required

The request didn’t name an automation. Put its id in the path; List automations has the ids.

keywords_required

An automation needs at least one keyword for fans to comment. On an update, keywords: [] is refused for the same reason.

too_many_keywords

One automation carries up to 20 keywords. Split them across automations on different posts, or keep the ones fans actually type.

keyword_has_space

From Validate an automation. The keyword has a space in it, and a keyword is matched as one word. Pick a single word, such as GUIDE or LINK.

keyword_too_long

From Validate an automation. The keyword is over 30 characters. Fans have to type it exactly, so short ones get used.

dm_message_required

An automation needs a dm_message: it’s the message the fan receives. On an update, "" is refused for the same reason.

dm_message_too_long

dm_message is up to 1,000 characters. Instagram truncates long messages, so shorter lands better anyway. From Validate an automation. The DM talks about a link, but no link_url was given, so the fan would be promised something that never arrives. Add the link, or reword the DM.

button_label_too_long

button_label is up to 20 characters. Instagram cuts off anything longer on the button.

public_reply_too_long

public_reply is up to 2,200 characters, Instagram’s length for a comment. A link has to start with https:// or http:// and name a host. param points at the field, such as link_url or links[1].url. link_title, and title on each item in links, is up to 20 characters. One message carries at most three links. That ceiling is Instagram’s, on every plan, so no plan lifts it. Keep the three that matter most. A follow gate or email gate holds the link back until the fan follows or shares an email. With no link, there’s nothing to hold back. Add link_url or links, or leave the gates off.

gate_label_too_long

follow_gate_visit_label and follow_gate_following_label are up to 20 characters each.

gate_copy_without_gate

You sent gate wording, such as follow_gate_message, but its gate is off, so nobody would ever read it. Turn the gate on, or leave the wording out.

opener_message_too_long

opener_message is up to 1,000 characters.

opener_plain_text_without_opener

opener_plain_text sets the shape of the opening message, so it needs an opener_message to apply to.

followup_message_too_long

followup_message is up to 1,000 characters.

followup_delay_out_of_range

followup_delay_minutes runs from 30 to 1,200 (20 hours). The ceiling is Instagram’s 24-hour messaging window minus headroom; the floor keeps a follow-up from landing on top of the first message.

followup_delay_without_message

There’s a followup_delay_minutes but no followup_message. Send the message with it, or leave the delay out.

followup_unreachable

This follow-up could never send. Instagram opens the 24-hour window only when the fan messages the account, and nothing in this automation asks them to: the single private reply a comment earns is the whole conversation. Add an opener_message, or turn on follow_gate or email_gate, and the follow-up becomes possible. Instagram’s rules explains the window.

status_invalid

status isn’t a value this endpoint takes. Set automation status takes live or paused; the status filter on List automations takes draft, live or paused.

limit_invalid

limit runs from 1 to 100.

cursor_invalid

The cursor isn’t one this list issued. Pass next_cursor back exactly as you received it, to the same endpoint with the same filters, or start again without a cursor. See Pagination.

days_invalid

days on Get automation stats runs from 1 to 90.

authentication_error (401)

The request didn’t carry a key inDM can accept. Authentication covers keys end to end.

api_key_missing

No Authorization header, or one that isn’t Bearer. Send Authorization: Bearer indm_....

api_key_invalid

The key isn’t one inDM issued. Most often it’s a copy that lost characters on the way, or a stray space or quote. Copy it again, or create a new key in Settings → API keys.

api_key_expired

The key passed its expiry date. Create a new one in Settings → API keys, and see rotation to switch without downtime.

api_key_revoked

Someone revoked this key, or the member who created it left the workspace. Create a new one.

permission_error (403)

insufficient_scope

This route needs a full key and the request used a read key. Use a key with full access for writes. See scopes.

plan_limit (403)

The workspace’s plan doesn’t include something this write needs. The API works on every plan; what a workspace can build through it is exactly what it can build in the app. message names what the write needs. The plans are described at indm.social/pricing.

automation_limit_reached

The workspace holds as many automations as its plan includes. Every automation counts, whatever its status, so pausing one doesn’t make room. The workspace’s plan includes fewer links per automation than this request sets. Links written into the message text count too when they go somewhere different from the attached links. Naming the attached link in a sentence is fine.

followup_requires_paid_plan

Follow-up messages are part of Growth. Everything else in the request can be saved: send it again without followup_message and followup_delay_minutes.

plan_limit_reached

The plan refused this write for a reason the codes above don’t cover. message names what it needs.

not_found (404)

Nothing with that id exists in this key’s workspace. An id from another workspace reads the same way: a key sees only its own.

account_not_found

No connected account with that id. List accounts has the ids.

media_not_found

No synced post or reel with that id. List media has the ids. A post published moments ago may not be synced yet; see Refresh content.

automation_not_found

No automation with that id. List automations has the ids.

refresh_job_not_found

No refresh with that job_id on that account. Use the job_id and account_id that Refresh content returned together.

route_not_found

There’s no endpoint at that path for that method. Check the path against the API reference, including the /v1 prefix.

conflict (409)

The request clashes with how things stand right now. Change the state, then retry.

live_automation_on_media

Another automation is already live on this post. A post runs one live automation at a time, so a fan who comments once gets one DM. Pause the other automation first, or choose a different post. Create an automation returns this too, so you never build a draft that can’t go live.

account_needs_reconnect

Instagram has paused this account’s connection, so nothing syncs or sends until it’s reconnected in the inDM app. Get account health says why and how it recovers.

rate_limited (429)

rate_limited

This key made more requests than its limit allows. Wait the number of seconds in the Retry-After header, then try again. See Rate limits.

api_error (500)

internal_error

Something failed on our side, and we log every one. It comes with 500, or 503 when inDM briefly can’t reach its database. Reads are safe to retry with backoff. For a write, read the current state before retrying, so a write that did land isn’t made twice. If it keeps happening, write to support@indm.social with the X-Request-Id.