> ## 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.

# Validate an automation

> A dry run. Checks a proposed comment-to-DM automation against the rules the engine
enforces and returns the normalised version together with anything that would make
it misfire: a keyword with a space in it, a button label Instagram would cut off, a
DM that promises a link it was never given.

It writes nothing, needs no post, and works with a `read` key, so you can check copy
before you have anywhere to put it.

Needs a `read` or `full` key.




## OpenAPI

````yaml post /automations/validate
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/validate:
    post:
      tags:
        - Automations
      summary: Validate an automation
      description: >
        A dry run. Checks a proposed comment-to-DM automation against the rules
        the engine

        enforces and returns the normalised version together with anything that
        would make

        it misfire: a keyword with a space in it, a button label Instagram would
        cut off, a

        DM that promises a link it was never given.


        It writes nothing, needs no post, and works with a `read` key, so you
        can check copy

        before you have anywhere to put it.


        Needs a `read` or `full` key.
      operationId: validateAutomation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutomationDraft'
            example:
              goal: Send the spring guide to anyone who comments GUIDE
              keyword: GUIDE
              dm_message: Here's the spring planting guide. Enjoy it.
              button_label: Send me the guide
              link_url: https://example.com/spring-guide
              language: en
      responses:
        '200':
          description: The check. `ready` is true when nothing would stop it working.
          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/AutomationDraftResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  schemas:
    AutomationDraft:
      type: object
      description: A proposed automation to check. Nothing is saved.
      required:
        - keyword
        - dm_message
      properties:
        goal:
          type: string
          description: What you want to happen, in your own words.
          example: Send the spring guide to anyone who comments GUIDE
        keyword:
          type: string
          description: The one word a fan comments to trigger it. Case-insensitive.
          example: GUIDE
        dm_message:
          type: string
          description: The direct message the fan receives.
          example: Here's the spring planting guide. Enjoy it.
        button_label:
          type: string
          description: The opt-in button's label. Up to 20 characters.
          example: Send me the guide
        public_reply:
          type: string
          description: A public reply posted under the fan's comment.
        link_url:
          type: string
          description: The link the DM delivers.
          example: https://example.com/spring-guide
        language:
          type: string
          description: >-
            The two-letter code of the language the copy is written in, such as
            `en`, `es` or `ko`.
          example: en
    AutomationDraftResult:
      type: object
      required:
        - specification
        - ready
        - problems
        - notes
      properties:
        specification:
          type: object
          description: The normalised automation, as inDM would build it.
          properties:
            trigger:
              type: string
              example: comment
            keyword:
              type: string
              description: The keyword, uppercased.
              example: GUIDE
            public_reply:
              type: string
            button_label:
              type: string
              description: >-
                The button label, with inDM's default filled in when you sent
                none.
              example: Send me the guide
            dm_message:
              type: string
              example: Here's the spring planting guide. Enjoy it.
            link_url:
              type: string
              example: https://example.com/spring-guide
            language:
              type: string
              example: en
            status_when_created:
              type: string
              description: Always `draft`.
              example: draft
        ready:
          type: boolean
          description: True when `problems` is empty, so nothing would stop it working.
          example: true
        problems:
          type: array
          description: >-
            What would make it misfire, in the order found. Empty when `ready`
            is true.
          items:
            $ref: '#/components/schemas/Problem'
          example: []
        notes:
          type: array
          description: Facts about how it will behave once live.
          items:
            $ref: '#/components/schemas/Caveat'
          example:
            - code: keywords_case_insensitive
              message: >-
                Keywords are case-insensitive, so GUIDE also matches guide and
                Guide.
            - code: created_as_draft
              message: Created as a draft. Nothing sends until it is set live.
    Problem:
      type: object
      description: One thing that would make a proposed automation misfire.
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: >-
            A stable code, listed on [Errors](/errors). The same code a create
            would be refused with, where one applies.
          example: button_label_too_long
        param:
          type: string
          description: The request field at fault. Left out when no single field is.
          example: button_label
        message:
          type: string
          description: What's wrong and how to fix it, in a sentence.
          example: >-
            The button label is 26 characters. Instagram shows up to 20, so it
            would be cut off.
    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
  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
    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.