RelayAPI
GuidesAutomations

Templates

Starter scaffolds for new automations — 4 quick-automation wizards and 4 generic blueprints.

Why templates

A full automation graph is a handful of nodes wired together with port-based edges. For the common patterns — comment-to-DM, welcome flows, FAQ routing, lead capture — the graph is mostly boilerplate. Templates capture those patterns: pass a small config object and the server generates a complete graph + entrypoint for you.

Templates are not a separate resource. You pass a template field to POST /v1/automations; the server runs buildGraphFromTemplate(kind, config), saves the resulting graph, creates matching entrypoints, and stores the original wizard input in automations.template_config (observability only — the graph is authoritative after creation).

Creating an automation from a template

POST /v1/automations
{
  "name": "Pizza promo",
  "channel": "instagram",
  "template": {
    "kind": "comment_to_dm",
    "config": {
      "post_ids": ["17895..."],
      "public_reply": "Sent!",
      "dm_message": {
        "blocks": [{ "id": "b1", "type": "text", "text": "Here's the link, {{contact.first_name}}!" }]
      },
      "once_per_user": true
    }
  }
}

The response is a full automation with:

  • status: "draft" (activate explicitly via POST /v1/automations/{id}/activate)
  • graph — the generated node/edge structure
  • created_from_template: "comment_to_dm" — used later for template-aggregated insights
  • template_config — the wizard input, preserved for reference

After creation you own the graph completely. Edit it with PUT /v1/automations/{id}/graph exactly like a hand-built automation; there is no "regenerate from template" concept.

The 8 templates

Generic scaffolds

Work on any channel, provide a minimal starting structure to edit.

KindDescription
blankEmpty graph, no entrypoint. Point of departure when you want to author everything yourself
welcome_flowGreeting message scaffold + basic info capture
faq_botKeyword-routed FAQ scaffold with common question branches
lead_captureGeneric email/phone capture → tag → confirmation

Config shape for blank:

{ "kind": "blank", "config": {} }

Config shape for welcome_flow, faq_bot, lead_capture:

{
  "kind": "welcome_flow",
  "config": {
    "welcome_message": { "blocks": [{ "id": "b1", "type": "text", "text": "Welcome {{contact.first_name}}!" }] },
    "dm_received_entrypoint": true
  }
}

Exact field sets vary per template; the server validates the config and returns a 422 with specific errors on mismatch.

Quick-automation wizards

Channel-specific patterns that ship the full end-to-end graph.

KindChannelsWhat it does
comment_to_dmIG, FBReply publicly on matching post comments + DM the commenter
story_leadsIGCapture leads from story replies
follower_growthIGContest flow — comment keyword triggers public reply + DM with contest rules + optional share mechanic
follow_to_dmIGWelcome DM on new follow

comment_to_dm config

{
  "kind": "comment_to_dm",
  "config": {
    "post_ids": ["17895..."],                        // specific posts, or omit for all
    "keywords": ["link", "info"],                    // optional — filter by comment keyword
    "public_reply": "Sent!",                         // optional comment reply
    "dm_message": {
      "blocks": [
        { "id": "b1", "type": "text", "text": "Here's the link, {{contact.first_name}}!" }
      ]
    },
    "once_per_user": true
  }
}

Builds a comment_created entrypoint and a graph with a public-reply action (if public_reply is set) + a message node sending the DM.

story_leads config

{
  "kind": "story_leads",
  "config": {
    "story_ids": null,                               // null = any story
    "dm_message": { "blocks": [{ "id": "b1", "type": "text", "text": "Thanks! Drop your email:" }] },
    "capture_field": "email",                        // custom field slug
    "success_tag": "story_lead"
  }
}

Builds a story_reply entrypoint + a graph that sends the DM, asks for an email via an input node, and on captured runs an action_group to set the custom field and add the tag.

follower_growth config

{
  "kind": "follower_growth",
  "config": {
    "contest_post_id": "17895...",
    "keywords": ["entry", "count me in"],
    "public_reply": "Entered!",
    "dm_message": {
      "blocks": [
        { "id": "b1", "type": "text", "text": "You're in! Share with a friend to double your chances." }
      ]
    },
    "entry_tag": "contest_entry",
    "require_tag_friend": false
  }
}

follow_to_dm config

{
  "kind": "follow_to_dm",
  "config": {
    "dm_message": {
      "blocks": [{ "id": "b1", "type": "text", "text": "Thanks for following, {{contact.first_name}}!" }]
    },
    "daily_cap": 200,
    "cooldown_min": 1440
  }
}

Builds a follow entrypoint with the cap + cooldown baked into re-entry rules.

Insights aggregation

automations.created_from_template stays on the row forever, which lets insights roll up across every automation created from the same template:

GET /v1/automations/insights?created_from_template=comment_to_dm&period=30d

Returns aggregate run counts, completion rate, and exit-reason breakdown across every comment_to_dm flow in the organization.

Editing a template's output

The automation returned by a template call is a normal automation. Use PUT /v1/automations/{id}/graph to change the graph, PATCH /v1/automation-entrypoints/{id} to tune the generated entrypoint, or DELETE /v1/automation-entrypoints/{id} + POST …/entrypoints to replace it. Nothing is special about template-generated automations at runtime.

Adding a template

Templates live under apps/api/src/services/automations/templates/. Each is a TemplateBuilder — a function (TemplateBuildInput) => { graph, entrypoints, name, description? }. Register it in templates/index.ts and the POST /v1/automations dispatcher picks it up automatically. No enum change, no migration.

Found something wrong? Help us improve this page.

On this page

Submit an Issue
Requires a GitHub account.View repo