> ## Documentation Index
> Fetch the complete documentation index at: https://docs.indm.social/llms.txt
> Use this file to discover all available pages before exploring further.

# Update an automation

> Changes an existing automation. Send only the fields you want to change:

- A field you leave out stays as it is.
- An empty string `""` removes an optional text field, such as `public_reply`,
  `opener_message` or `followup_message`.
- `keywords` and `links` replace the whole list. Sending `links: []` removes every
  link.

It does not change whether the automation is live or paused;
[Set automation status](/api-reference/automations/set-automation-status) does that.
On a live automation the change is in effect for the next comment.

Needs a `full` key.




## OpenAPI

````yaml patch /automations/{automation_id}
openapi: 3.1.0
info:
  title: inDM API
  version: 1.0.0
  summary: >-
    Build, launch and read Instagram comment-to-DM automations from your own
    code.
  description: >
    The inDM API gives your code the same reach as the inDM app: list the posts
    and reels

    inDM has synced, pull in new ones, build automations on them, set them live
    and read

    how they are doing.


    Every request is authenticated with an API key created in **Settings → API
    keys**.

    Keys belong to one workspace and carry a scope, `read` or `full`. Keys are
    server-side

    secrets: the API sends no CORS headers, so a browser can't call it directly.


    Nothing sends through this API. No DM, broadcast or public reply leaves
    Instagram by

    this path, and every automation it creates starts as a `draft`. Setting one
    `live` is

    the only call that changes what people on Instagram receive.
  contact:
    name: inDM support
    email: support@indm.social
    url: https://docs.indm.social
servers:
  - url: https://api.indm.social/v1
    description: Production
security:
  - apiKey: []
tags:
  - name: Workspace
    description: The workspace and API key behind a request.
  - name: Accounts
    description: Connected Instagram accounts, their health, and content refreshes.
  - name: Media
    description: Posts and reels inDM has synced from Instagram.
  - name: Automations
    description: Comment-to-DM automations. Created as drafts; set live when you're ready.
paths:
  /automations/{automation_id}:
    patch:
      tags:
        - Automations
      summary: Update an automation
      description: >
        Changes an existing automation. Send only the fields you want to change:


        - A field you leave out stays as it is.

        - An empty string `""` removes an optional text field, such as
        `public_reply`,
          `opener_message` or `followup_message`.
        - `keywords` and `links` replace the whole list. Sending `links: []`
        removes every
          link.

        It does not change whether the automation is live or paused;

        [Set automation
        status](/api-reference/automations/set-automation-status) does that.

        On a live automation the change is in effect for the next comment.


        Needs a `full` key.
      operationId: updateAutomation
      parameters:
        - $ref: '#/components/parameters/AutomationId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutomationUpdate'
            example:
              dm_message: Here's the spring planting guide, with the new seed list.
              public_reply: ''
      responses:
        '200':
          description: The automation as saved.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            RateLimit-Limit:
              $ref: '#/components/headers/RateLimit-Limit'
            RateLimit-Remaining:
              $ref: '#/components/headers/RateLimit-Remaining'
            RateLimit-Reset:
              $ref: '#/components/headers/RateLimit-Reset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutomationWriteResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  parameters:
    AutomationId:
      name: automation_id
      in: path
      required: true
      description: >-
        The automation `id` from [List
        automations](/api-reference/automations/list-automations).
      schema:
        type: string
        format: uuid
      example: 9a4b1c7e-2d3f-4a5b-8c6d-1e2f3a4b5c6d
  schemas:
    AutomationUpdate:
      description: >
        The fields to change. Anything you leave out stays as it is. `""`
        removes an optional

        text field. `keywords` and `links` replace the whole list.
      allOf:
        - $ref: '#/components/schemas/AutomationFields'
    AutomationWriteResult:
      description: The automation as saved, and anything that was adjusted on the way in.
      allOf:
        - $ref: '#/components/schemas/Automation'
        - type: object
          required:
            - caveats
          properties:
            caveats:
              type: array
              description: >
                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.
              items:
                $ref: '#/components/schemas/Caveat'
    AutomationFields:
      type: object
      description: The fields create and update share.
      properties:
        name:
          type: string
          description: A short name for your own list in inDM.
          example: Spring guide reel
        keywords:
          type: array
          minItems: 1
          maxItems: 20
          description: >
            The words that trigger it. Case-insensitive, so `GUIDE` also matches
            `guide`.

            A keyword belongs to one automation. Up to 20.
          items:
            type: string
          example:
            - GUIDE
        dm_message:
          type: string
          maxLength: 1000
          description: >
            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.
          example: Here's the spring planting guide. Enjoy it.
        button_label:
          type: string
          maxLength: 20
          description: The opt-in button's label. Up to 20 characters.
          example: Send me the guide
        public_reply:
          type: string
          maxLength: 2200
          description: >-
            A public reply posted under the fan's comment. Up to 2,200
            characters.
          example: Sent it to your DMs.
        link_url:
          type: string
          format: uri
          description: >
            The one link the DM delivers. Starts with `https://` or `http://`.
            For more than

            one link, use `links` instead.
          example: https://example.com/spring-guide
        link_title:
          type: string
          maxLength: 20
          description: The label on the link's button. Up to 20 characters.
          example: Open the guide
        links:
          type: array
          maxItems: 3
          description: >
            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.
          items:
            $ref: '#/components/schemas/Link'
        opener_message:
          type: string
          maxLength: 1000
          description: >
            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.
        opener_plain_text:
          type: boolean
          description: >
            Send the opener as plain text with no button, so any reply counts as
            the

            opt-in. Only meaningful with `opener_message`.
        follow_gate:
          type: boolean
          description: >
            Ask the fan to follow the account before the link arrives. Needs a
            link. After

            four asks the link is delivered anyway.
        follow_gate_message:
          type: string
          description: >-
            Your own words for the follow ask, in place of inDM's. Needs
            `follow_gate`.
        follow_gate_visit_label:
          type: string
          maxLength: 20
          description: >-
            The label on the button that opens your profile. Up to 20
            characters. Needs `follow_gate`.
        follow_gate_following_label:
          type: string
          maxLength: 20
          description: >-
            The label on the button a fan taps once they follow. Up to 20
            characters. Needs `follow_gate`.
        email_gate:
          type: boolean
          description: >-
            Ask the fan for an email address before the link arrives. Needs a
            link.
        email_gate_message:
          type: string
          description: >-
            Your own words for the email ask, in place of inDM's. Needs
            `email_gate`.
        followup_message:
          type: string
          maxLength: 1000
          description: >
            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.
        followup_delay_minutes:
          type: integer
          minimum: 30
          maximum: 1200
          description: >
            How 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`.
    Automation:
      description: >
        An automation's full setup: everything [Update an
        automation](/api-reference/automations/update-automation)

        can change, as it is stored now. The names match the update body, so you
        can edit

        what you read and send it back. The one difference: `public_replies`
        lists every

        public reply, where a create or update body sets one as `public_reply`.
      allOf:
        - $ref: '#/components/schemas/AutomationSummary'
        - type: object
          required:
            - dm_message
            - button_label
            - public_replies
            - links
            - opener_message
            - opener_plain_text
            - follow_gate
            - email_gate
            - follow_gate_message
            - follow_gate_visit_label
            - follow_gate_following_label
            - email_gate_message
            - followup_message
            - followup_delay_minutes
          properties:
            dm_message:
              type: string
              description: >-
                The message carrying the link. With an opener, this is the
                second message.
              example: Here's the spring planting guide. Enjoy it.
            button_label:
              type: string
              description: The opt-in button's label.
              example: Send me the guide
            public_replies:
              type: array
              description: >-
                The public replies inDM posts under a fan's comment, one per
                comment. Empty when there are none.
              items:
                type: string
              example:
                - Sent it to your DMs.
            links:
              type: array
              description: >-
                The links the DM delivers, in the order the fan sees them. Empty
                when there are none.
              items:
                $ref: '#/components/schemas/Link'
            opener_message:
              type: string
              description: The opt-in message sent first. Empty when there is no opener.
              example: ''
            opener_plain_text:
              type: boolean
              description: Whether the opener is sent as plain text with no button.
              example: false
            follow_gate:
              type: boolean
              description: Whether the fan is asked to follow before the link arrives.
              example: false
            email_gate:
              type: boolean
              description: >-
                Whether the fan is asked for an email address before the link
                arrives.
              example: false
            follow_gate_message:
              type: string
              description: >-
                Your own words for the follow ask. Empty when inDM's wording is
                used.
              example: ''
            follow_gate_visit_label:
              type: string
              description: >-
                The label on the button that opens your profile. Empty for
                inDM's.
              example: ''
            follow_gate_following_label:
              type: string
              description: >-
                The label on the button a fan taps once they follow. Empty for
                inDM's.
              example: ''
            email_gate_message:
              type: string
              description: >-
                Your own words for the email ask. Empty when inDM's wording is
                used.
              example: ''
            followup_message:
              type: string
              description: The second message sent later. Empty when there is no follow-up.
              example: ''
            followup_delay_minutes:
              type: integer
              description: >-
                How long after the first message the follow-up goes out. `0`
                when there is no follow-up.
              example: 0
    Caveat:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: A stable code for what was adjusted.
          example: followup_goes_to_everyone
        message:
          type: string
          description: What it means, in a sentence.
          example: >-
            The follow-up goes to everyone who received the first message,
            including people who already tapped the link.
    Error:
      type: object
      description: Every error has this shape.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
            - doc_url
          properties:
            type:
              type: string
              description: The family of error. Each maps to one HTTP status.
              enum:
                - invalid_request
                - authentication_error
                - permission_error
                - plan_limit
                - not_found
                - conflict
                - rate_limited
                - api_error
            code:
              type: string
              description: >
                A stable, specific code. Branch on this, never on `message`.
                Every code is

                listed on [Errors](/errors).
              example: dm_message_too_long
            message:
              type: string
              description: >-
                A sentence for a person, saying what happened and what to do
                next. It may change; don't parse it.
            param:
              type: string
              description: >-
                The request field the error is about. Left out when no single
                field is.
              example: dm_message
            doc_url:
              type: string
              format: uri
              description: A link to this code on the [Errors](/errors) page.
              example: https://docs.indm.social/errors#dm_message_too_long
    Link:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: Where the link goes. Starts with `https://` or `http://`.
          example: https://example.com/spring-guide
        title:
          type: string
          maxLength: 20
          description: The label on the link's button. Up to 20 characters.
          example: Open the guide
    AutomationSummary:
      type: object
      description: An automation as it appears in a list.
      required:
        - id
        - name
        - status
        - trigger
        - binding
        - account_id
        - keywords
        - dm_sent_count
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          example: 9a4b1c7e-2d3f-4a5b-8c6d-1e2f3a4b5c6d
        name:
          type: string
          example: Spring guide reel
        status:
          type: string
          enum:
            - draft
            - live
            - paused
          example: live
        trigger:
          type: string
          description: What fires it, such as `comment`.
          example: comment
        binding:
          type: string
          description: >
            How it is attached to content: `specific` for one post, `next` for
            the next post

            the account publishes, `any` for every post.
          example: specific
        account_id:
          type: string
          format: uuid
          example: 6f1c2a9e-3b7d-4e21-9a55-0c8d2f4b7e10
        media_id:
          type: string
          format: uuid
          description: The post it is attached to. Present when `binding` is `specific`.
          example: 3d2a7f10-9c4e-4b8a-a1f2-6e0b5d7c9a31
        keywords:
          type: array
          description: The words that trigger it, as stored.
          items:
            type: string
          example:
            - GUIDE
        dm_sent_count:
          type: integer
          description: DMs this automation has sent since it was created.
          example: 182
        created_at:
          type: string
          format: date-time
          example: '2026-11-05T09:02:11Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-11-05T09:04:30Z'
  headers:
    X-Request-Id:
      description: >-
        A unique id for this request. Include it when you write to support and
        we can find the request at once.
      schema:
        type: string
      example: req_8Qm2ZcY4vN7tLp1K
    RateLimit-Limit:
      description: >-
        Requests this key may make per minute, across every route. Sent once the
        key is accepted.
      schema:
        type: integer
      example: 120
    RateLimit-Remaining:
      description: >-
        Requests left in the current one-minute window. `0` when a write is
        refused for the write limit.
      schema:
        type: integer
      example: 117
    RateLimit-Reset:
      description: Seconds until the current window resets.
      schema:
        type: integer
      example: 42
    Retry-After:
      description: Seconds to wait before trying again.
      schema:
        type: integer
      example: 18
  responses:
    BadRequest:
      description: >-
        The request can't be processed as sent. `param` names the field when
        there is one.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: invalid_request
              code: button_label_too_long
              message: >-
                The button label is 26 characters. Instagram shows up to 20, so
                it would be cut off.
              param: button_label
              doc_url: https://docs.indm.social/errors#button_label_too_long
    Unauthorized:
      description: The API key is missing, malformed, expired or revoked.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: authentication_error
              code: api_key_expired
              message: >-
                This API key expired on 3 Feb 2027. Create a new one under
                Settings → API keys.
              doc_url: https://docs.indm.social/errors#api_key_expired
    Forbidden:
      description: >
        The key's scope doesn't cover this route (`permission_error`), or the
        workspace's

        plan doesn't include what this write needs (`plan_limit`).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            insufficient_scope:
              summary: A read key on a write route
              value:
                error:
                  type: permission_error
                  code: insufficient_scope
                  message: >-
                    This key is read-only, and POST /v1/automations changes
                    things. Use a key with full access.
                  doc_url: https://docs.indm.social/errors#insufficient_scope
            plan_limit:
              summary: A write the plan doesn't include
              value:
                error:
                  type: plan_limit
                  code: followup_requires_paid_plan
                  message: >-
                    Follow-up messages send on Growth. Everything else in this
                    request can be saved without the follow-up.
                  param: followup_message
                  doc_url: https://docs.indm.social/errors#followup_requires_paid_plan
    NotFound:
      description: Nothing with that id exists in this key's workspace.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: not_found
              code: media_not_found
              message: >-
                There's no post with that id in this workspace. GET /v1/media
                lists them; refresh the account first if it was just published.
              param: media_id
              doc_url: https://docs.indm.social/errors#media_not_found
    RateLimited:
      description: >-
        This key went past its rate limit. Wait for `Retry-After` seconds, then
        try again.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        RateLimit-Limit:
          $ref: '#/components/headers/RateLimit-Limit'
        RateLimit-Remaining:
          $ref: '#/components/headers/RateLimit-Remaining'
        RateLimit-Reset:
          $ref: '#/components/headers/RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: rate_limited
              code: rate_limited
              message: >-
                That's more than 120 requests a minute on one key. Wait 18s and
                try again.
              doc_url: https://docs.indm.social/errors#rate_limited
    ServerError:
      description: >
        Something failed on our side. Retrying with backoff is safe for reads.
        The same body

        comes with `503` when inDM briefly can't reach its database.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: api_error
              code: internal_error
              message: >-
                Something went wrong on our end. Try again; if it keeps
                happening, quote request req_8Qm2ZcY4vN7tLp1K to
                support@indm.social.
              doc_url: https://docs.indm.social/errors#internal_error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: indm_ API key
      description: >
        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.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.