RelayAPI
GuidesAutomations

Automations

Build visual flows that trigger on social events and orchestrate multi-step conversations across Instagram, Messenger, WhatsApp, and Telegram.

Overview

Automations are RelayAPI's flow-based engine. A flow reacts to events on a connected social channel — comments, DMs, keywords, scheduled times, tag changes, third-party webhooks — and executes a directed graph that can send messages, capture replies, branch on conditions, mutate the contact, call external APIs, and hand control off to another flow.

Supported channels: Instagram, Facebook Messenger, WhatsApp, and Telegram. Each automation is bound to exactly one channel; the builder surfaces channel-aware warnings when you use a feature that channel doesn't support.

Core concepts

An automation has four moving parts:

  1. Graph — the flow itself. Stored as a single JSONB document on the automation row (nodes, edges, root_node_key). Nodes have typed input and output ports; edges connect one node's output port to another node's input port. No label fallbacks, no implicit wiring — if a port has no outgoing edge, the run ends there.
  2. Entrypoints — the events that start a run. A flow can have multiple entrypoints (several keywords, a DM kind, a webhook) and the matcher picks the most specific one on each event.
  3. Bindings — channel-surface attachments on a social account. There are five: default_reply, welcome_message, conversation_starter, main_menu, and ice_breaker. Bindings run a flow when an entrypoint doesn't match.
  4. Runs — execution instances. One row per enrolled contact per flow, with append-only per-node logs in automation_step_runs for inspection.

Edges are port-based

Every edge connects four things:

{ "from_node": "greet", "from_port": "button.btn_large", "to_node": "order_large", "to_port": "in" }

There is no label field and no fallback — the port key IS the routing primitive. A message node with two branch buttons exposes button.<id> output ports; the runner follows the edge matching the port the handler exited through. If you don't wire a button port, pressing that button ends the run on that path. Ports are derived deterministically from node config on every save, so adding a button creates its port, deleting one removes the port and prunes orphan edges with a warning.

Lifecycle

draft → active → paused → archived
  • draft — initial state for newly created automations; nothing fires.
  • active — entrypoints and bindings match live events.
  • paused — no new runs start; in-flight runs keep going unless stopped.
  • archived — read-only; no runs start.

There is no revisions / draft-published split. Every automation has exactly one live graph. Edits are instantly live. If an in-flight run's current node disappears after an edit, the run exits cleanly with exit_reason = "graph_changed" — it never corrupts state.

Quickstart

The fastest path is a template. One POST creates the flow, generates the graph, and attaches an initial entrypoint:

curl -X POST https://api.relayapi.dev/v1/automations \
  -H "Authorization: Bearer rlay_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Link-in-bio giveaway",
    "channel": "instagram",
    "template": {
      "kind": "comment_to_dm",
      "config": {
        "post_ids": ["17895..."],
        "keywords": ["link", "giveaway"],
        "public_reply": "Sent!",
        "dm_message": { "blocks": [{ "id": "b1", "type": "text", "text": "Here you go, {{contact.first_name}}!" }] },
        "once_per_user": true
      }
    }
  }'

The call returns the full automation with its generated graph as a draft. Inspect, tweak if needed via PUT /v1/automations/{id}/graph, then activate with POST /v1/automations/{id}/activate.

See Templates for the full catalog and per-template config shapes.

Authoring a custom graph

For anything a template doesn't cover, create a blank automation and replace the graph:

# 1. Create
POST /v1/automations
{ "name": "Welcome + ask email", "channel": "instagram", "template": { "kind": "blank", "config": {} } }

# 2. Replace graph
PUT /v1/automations/{id}/graph
{
  "graph": {
    "schema_version": 1,
    "root_node_key": "greet",
    "nodes": [
      {
        "key": "greet",
        "kind": "message",
        "config": {
          "blocks": [{ "id": "b1", "type": "text", "text": "Hey {{contact.first_name}}! Want my free guide?" }],
          "wait_for_reply": false
        },
        "ports": []
      },
      {
        "key": "ask_email",
        "kind": "input",
        "config": { "prompt": "Drop your email and I'll send it over.", "input_type": "email", "save_to_field": "email" },
        "ports": []
      }
    ],
    "edges": [
      { "from_node": "greet", "from_port": "next", "to_node": "ask_email", "to_port": "in" }
    ]
  }
}

# 3. Add an entrypoint
POST /v1/automations/{id}/entrypoints
{ "kind": "dm_received", "channel": "instagram", "social_account_id": "acc_abc123" }

# 4. Activate
POST /v1/automations/{id}/activate

On save, the server derives each node's ports array, runs the validator, and stores the canonicalized graph. Validation errors block activation and auto-pause the automation; warnings (orphan button ports, etc.) don't.

Merge tags

Text blocks, button labels, input prompts, and webhook bodies all support {{...}} substitution:

  • {{contact.first_name}}, {{contact.email}}, {{contact.phone}}, {{contact.custom_fields.<slug>}}
  • {{context.<key>}} — values captured earlier in the same run (input replies, HTTP response extracts, webhook payload mappings)
  • {{run.id}}, {{run.started_at}}
  • {{account.name}}, {{account.handle}}

Unknown paths surface as warnings at save time; unresolved tags at runtime render as an empty string.

Availability notes

  • AI nodes — dropped from v1. ai_step, ai_agent, and ai_intent_router are archived and will return in a later release.
  • Stubbed bindingsconversation_starter, main_menu, and ice_breaker are stored and configurable in the UI in v1 but do not yet push to the platform. Platform sync lands in v1.1.
  • Broadcasts are a separate system and are not part of automations.
  • Nodes — the 10 node kinds, ports, config shapes, action catalog.
  • Triggers — entrypoint kinds, bindings, conflict resolution, webhook entrypoints.
  • Runs — run lifecycle, step-run inspection, stopping a run.
  • Templates — the 8 starter templates and their config shapes.

Found something wrong? Help us improve this page.

On this page

Submit an Issue
Requires a GitHub account.View repo