Nimply Developers

Automations

Build automations from your app, ChatGPT or Claude — start from a recipe or a list of steps, test, then switch on.

An automation does something for you when a trigger fires: "when a post fails, alert me", "every morning, have my Trend Scout find a topic and my Designer make a carousel". They are the same automations you see on the Automations page in the app, and you can open and edit any of them there.

With the API you can:

  • list the building blocks (step types) and ready-made recipes,
  • create an automation from a recipe, from a list of steps, or from a full graph,
  • test it, switch it on or off, run it now, and see its runs,
  • change or delete it.

Scopes: automations:read to read, automations:write for everything that creates, changes, tests or runs. Both are opt-in.

The safe order: draft → test → switch on

Every automation you create through the API starts as a draft. A draft never runs on its own.

  1. Create it (POST /v1/automations or POST /v1/automations/from-recipe).
  2. Test it (POST /v1/automations/{id}/test). Steps that would change something are only previewed.
  3. Show the user what it will do, and switch it on (POST /v1/automations/{id}/activate) only when they agree.

Endpoints

MethodPathScopeWhat it does
GET/v1/automation-step-typesautomations:readTriggers, actions and logic you can use, with their settings
GET/v1/automation-recipesautomations:readReady-made automations and the blanks to fill
GET/v1/automationsautomations:readYour automations (status filter; up to 100, most recently changed first)
POST/v1/automationsautomations:writeCreate a draft from steps or graph
POST/v1/automations/from-recipeautomations:writeCreate a draft from a recipe
GET/v1/automations/{id}automations:readOne automation, in plain words and as a graph
PATCH/v1/automations/{id}automations:writeChange name, description or steps
DELETE/v1/automations/{id}automations:writeDelete it and its run history
POST/v1/automations/{id}/activateautomations:writeSwitch it on
POST/v1/automations/{id}/pauseautomations:writeSwitch it off
POST/v1/automations/{id}/testautomations:writeTest run with sample data
POST/v1/automations/{id}/runautomations:writeRun it once for real
GET/v1/automations/{id}/runsautomations:readRecent runs (limit up to 100)
GET/v1/automation-runs/{id}automations:readOne run, step by step

Tests are limited to 20 requests per minute per key and live runs to 10 per minute, on top of the general rate limit.

Step types

GET /v1/automation-step-types lists every building block you can use through the API:

  • Triggers start an automation: a schedule, a button press (trigger.manual), a workspace event such as "Post failed", a new article in a feed, a new comment, and more.
  • Actions do something: run an agent, create a draft post, make a design, send a notification, tag a person, and more.
  • Logic: logic.if (branch on a value) and logic.delay (wait).

Here is the If step from that list:

{
  "data": [
    {
      "key": "logic.if",
      "kind": "logic",
      "name": "If condition",
      "description": "Branches the workflow: continues on the true or false path.",
      "fields": [
        { "key": "left", "type": "text", "label": "Value", "required": true, "multiple": false },
        {
          "key": "operator",
          "type": "select",
          "label": "Operator",
          "required": true,
          "multiple": false,
          "options": [
            { "value": "equals", "label": "equals" },
            { "value": "not_equals", "label": "does not equal" },
            { "value": "contains", "label": "contains" },
            { "value": "gt", "label": "greater than" },
            { "value": "lt", "label": "less than" },
            { "value": "exists", "label": "exists" },
            { "value": "not_exists", "label": "does not exist" }
          ]
        },
        { "key": "right", "type": "text", "label": "Compare to", "required": false, "multiple": false }
      ],
      "outputs": ["true", "false"],
      "costsCredits": false,
      "activateInApp": false
    }
  ]
}
  • fields are the step's settings. Put them in the step's params. Text settings can use values from earlier steps: {{trigger.…}} and {{nodes.<id>.…}}.
  • costsCredits: true means the step uses AI credits when it runs (running an agent, making a design, sorting inbox messages).
  • activateInApp: true marks a step that messages customers with no human check. See What stays in the app.

Recipes

Recipes are the quickest start. GET /v1/automation-recipes lists them with their blanks: the things you choose, usually which agent to run.

curl -X POST "https://api.nimply.io/v1/automations/from-recipe" \
  -H "Authorization: Bearer $NIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipeId": "daily-trend-carousel",
    "values": {
      "scoutInstanceId": "3f0c2a5e-1b7d-4c8e-9a6f-2d4b8e1c7a90",
      "designerInstanceId": "8e1c7a90-2d4b-4c8e-9a6f-3f0c2a5e1b7d"
    }
  }'

Agent blanks take an agent id from GET /v1/agents. The agent must be made from one of the blank's templateIds. Blanks you leave out stay empty: the draft is created, but it can't be switched on until they are filled (with PATCH or in the app).

Build from steps

For your own automation, send a list of steps: the trigger first, then the actions. Without edges, the steps run one after another in the order you send them.

curl -X POST "https://api.nimply.io/v1/automations" \
  -H "Authorization: Bearer $NIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monday planning reminder",
    "steps": [
      { "type": "trigger.schedule", "name": "Every Monday at 9", "params": { "cron": "0 9 * * 1" } },
      { "type": "action.notify", "params": { "target": "inapp", "message": "Time to plan the week" } }
    ]
  }'

Schedules use five-field cron, in UTC.

Branch with If

To branch, give the steps your own ids and add edges. Each edge out of an If step needs a sourceHandle of "true" or "false":

{
  "name": "Failure triage",
  "steps": [
    { "id": "trigger", "type": "trigger.event", "params": { "event": "post.failed" } },
    {
      "id": "check",
      "type": "logic.if",
      "name": "Auth error?",
      "params": { "left": "{{trigger.error}}", "operator": "contains", "right": "token" }
    },
    {
      "id": "reconnect",
      "type": "action.notify",
      "params": { "target": "inapp", "message": "{{trigger.channel.name}} needs reconnecting." }
    },
    {
      "id": "generic",
      "type": "action.notify",
      "params": { "target": "inapp", "message": "Post failed on {{trigger.channel.name}}: {{trigger.error}}" }
    }
  ],
  "edges": [
    { "source": "trigger", "target": "check" },
    { "source": "check", "target": "reconnect", "sourceHandle": "true" },
    { "source": "check", "target": "generic", "sourceHandle": "false" }
  ]
}

Or send the full graph

If a list can't express your layout, send graph instead of steps: { "nodes": [...], "edges": [...] }, the same shape GET /v1/automations/{id} returns. Each node needs an id and a type; name, params and a canvas position are optional. Send steps or graph, not both.

The automation

Both ways return 201 with the draft:

{
  "id": "9d2f4b1a-6c3e-4f8a-b5d7-1e0a2c4b6d8f",
  "name": "Monday planning reminder",
  "description": null,
  "status": "DRAFT",
  "pausedReason": null,
  "managedBy": null,
  "trigger": { "type": "trigger.schedule", "summary": "On a schedule (0 9 * * 1 UTC)" },
  "steps": [
    {
      "id": "n2",
      "type": "action.notify",
      "name": "Send notification",
      "summary": "target: inapp · message: Time to plan the week"
    }
  ],
  "graph": {
    "nodes": [
      {
        "id": "n1",
        "type": "trigger.schedule",
        "name": "Every Monday at 9",
        "position": { "x": 80, "y": 200 },
        "params": { "cron": "0 9 * * 1" }
      },
      {
        "id": "n2",
        "type": "action.notify",
        "position": { "x": 420, "y": 200 },
        "params": { "target": "inapp", "message": "Time to plan the week" }
      }
    ],
    "edges": [{ "id": "e1", "source": "n1", "target": "n2", "sourceHandle": "main" }]
  },
  "tags": [],
  "version": 1,
  "activateInApp": false,
  "lastRunAt": null,
  "nextRunAt": null,
  "createdAt": "2026-10-29T09:00:00.000Z",
  "updatedAt": "2026-10-29T09:00:00.000Z",
  "appUrl": "https://app.nimply.io/workspace/…/automations/9d2f4b1a-…"
}

trigger.summary and each step's summary describe the automation in plain words. Show them to the user before you switch it on.

Draft, test, switch on

Test runs the automation once with sample data, or with your own triggerData (available to the steps as {{trigger.…}}):

curl -X POST "https://api.nimply.io/v1/automations/9d2f4b1a-6c3e-4f8a-b5d7-1e0a2c4b6d8f/test" \
  -H "Authorization: Bearer $NIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Steps that would change something (create a post, send a message, notify) are only previewed. Steps that use AI can still use credits. The answer is 200 with the finished test run.

Switch on with POST /v1/automations/{id}/activate. Nimply checks everything first: one trigger, every step connected, required settings filled, a valid schedule. If something is wrong you get 422 INVALID_GRAPH, with one problem per entry in errors, so you can fix them all at once:

{
  "type": "https://developer.nimply.io/docs/errors#unprocessable-entity",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Step \"n2\" (Send notification): missing required field \"Message\" (message)",
  "code": "INVALID_GRAPH",
  "errors": ["Step \"n2\" (Send notification): missing required field \"Message\" (message)"],
  "instance": "/v1/automations/9d2f4b1a-6c3e-4f8a-b5d7-1e0a2c4b6d8f/activate"
}

Once on, it runs by itself every time its trigger fires. Switching on an automation that starts on a new comment also turns on the Inbox for the channels it watches.

Switch off with POST /v1/automations/{id}/pause.

Run now with POST /v1/automations/{id}/run. This is a real run, not a test, whether or not the automation is switched on. It works only for automations started by hand or on a schedule; one that starts on an event returns 422 RUN_NEEDS_EVENT (test it instead). The answer is 202 with the run; read it with GET /v1/automation-runs/{id}. Live runs count toward your plan's monthly runs.

Change an automation

PATCH /v1/automations/{id} changes name, description (null clears it), or what it does (steps + edges, or graph). New steps replace all the old ones.

Every automation has a version that goes up each time its steps change. Send the version you read (or an If-Match: "3" header). If someone changed it in the meantime, nothing is saved and you get 409 VERSION_CONFLICT: read it again, then retry.

curl -X PATCH "https://api.nimply.io/v1/automations/9d2f4b1a-6c3e-4f8a-b5d7-1e0a2c4b6d8f" \
  -H "Authorization: Bearer $NIMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Monday planning nudge", "version": 1 }'

An automation that is switched on must stay ready to run, so a change to its steps is checked the same way as switching on.

Managed automations are read-only

Some automations belong to something else. Their managedBy tells you:

  • agent: it follows an agent, for example the schedule of a LinkedIn Ghostwriter. Change, pause or remove the agent instead.
  • nimply: Nimply runs it for a feature you switch on in the app (Smart inbox triage).

You can read them, but changing, testing, running or deleting one returns 409 MANAGED_AUTOMATION.

What stays in the app

Some things can't be done through the API at all:

  • Web requests to outside addresses (action.http_request).
  • Stored secrets ({{secret:…}}).
  • Webhook triggers (trigger.webhook), whose secret URL starts the automation.

These step types aren't listed, and sending one returns 422 STEP_NOT_ALLOWED. You can add them yourself on the Automations page. An automation that already has one (built in the app) can still be read, but testing, running or switching it on through the API returns 422 SET_IN_APP.

Two steps message customers with no human check: Reply in inbox (action.inbox_reply) and Reply & DM by keyword (action.comment_dm, comment-to-DM). You can build and test automations with them through the API. Switching them on, or running them live, happens only in the Nimply app, where the person sees what they agree to. Such automations have activateInApp: true. Trying returns 422 SET_IN_APP with appUrl, the link to the automation in the app.

Runs

{
  "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
  "automationId": "9d2f4b1a-6c3e-4f8a-b5d7-1e0a2c4b6d8f",
  "mode": "TEST",
  "status": "SUCCEEDED",
  "triggerType": "manual",
  "creditsUsed": 0,
  "error": null,
  "startedAt": "2026-10-29T09:00:00.000Z",
  "finishedAt": "2026-10-29T09:00:01.000Z",
  "steps": [
    { "nodeId": "n1", "type": "trigger.schedule", "status": "SUCCEEDED", "error": null },
    { "nodeId": "n2", "type": "action.notify", "status": "SUCCEEDED", "error": null }
  ]
}
  • mode is TEST or LIVE. status is RUNNING, WAITING (at a delay step), SUCCEEDED, FAILED, CANCELED or SKIPPED.
  • Each step reports only its status and error. What a step received or produced is never returned, because it can hold customer messages and other private data. Open the run in the app to see more.

Limits

  • At most 30 steps (and 40 connections) per automation.
  • At most 20 automations switched on per workspace (403 ACTIVE_AUTOMATION_LIMIT).
  • Your plan sets how many automations you can have (403 AUTOMATION_QUOTA_EXCEEDED) and how many live runs you get each month.
  • Live runs are also capped at 60 an hour and 5 at once per workspace (429).

Who can do what

Keys act for a person: the user who approved the connection (OAuth), or the person who made the API key. That person's workspace role decides what the call may do:

ActionRoles
Read step types, recipes, automations and runsAny member
Create, change, testOwner, admin, editor
Switch on, switch off, run now, deleteOwner, admin

Otherwise the call fails with 403 and code INSUFFICIENT_ROLE.

Errors

StatuscodeMeaning
403INSUFFICIENT_ROLEThe person the key acts for needs a higher workspace role
403AUTOMATION_QUOTA_EXCEEDEDYour plan allows no more automations
403ACTIVE_AUTOMATION_LIMIT20 automations are already switched on; pause one first
403—The key or connection is missing an automations:* scope
404RECIPE_NOT_FOUNDNo recipe with that id
409VERSION_CONFLICTIt changed since you read it; read it again, then retry
409MANAGED_AUTOMATIONIt belongs to an agent or a Nimply feature and is read-only
422STEP_NOT_ALLOWEDA step type or stored secret the API can't add
422INVALID_GRAPHNot ready (or not valid); errors lists every problem
422INVALID_INPUTSend steps or graph, not both; edges only with steps
422INVALID_VALUESAn unknown recipe blank, or an agent that isn't in this workspace or doesn't fit the blank
422SET_IN_APPOnly the Nimply app can switch this on or run it; see appUrl
422RUN_NEEDS_EVENTIt starts on an event, so it can't be run by hand; test it instead
429—Too many requests, or the hourly / at-once run caps; retry after Retry-After seconds

From ChatGPT, Claude and other assistants

The MCP server (version 0.7.0 and later) has matching tools: list_automation_step_types, list_automation_recipes, list_automations, get_automation, create_automation, create_automation_from_recipe, update_automation, set_automation_status, test_automation, run_automation, get_automation_run and delete_automation. Ask things like:

  • "Every Monday, make a trend carousel with my Trend Scout and Designer."
  • "Alert me in Slack when a post fails."
  • "Pause my planning reminder."

The assistant creates a draft, tests it, and switches it on only after you confirm.

Connections made before these tools existed don't have automation access yet. Reconnect Nimply in your assistant and approve the automation permissions.

On this page