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 viaPOST /v1/automations/{id}/activate)graph— the generated node/edge structurecreated_from_template: "comment_to_dm"— used later for template-aggregated insightstemplate_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.
| Kind | Description |
|---|---|
blank | Empty graph, no entrypoint. Point of departure when you want to author everything yourself |
welcome_flow | Greeting message scaffold + basic info capture |
faq_bot | Keyword-routed FAQ scaffold with common question branches |
lead_capture | Generic 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.
| Kind | Channels | What it does |
|---|---|---|
comment_to_dm | IG, FB | Reply publicly on matching post comments + DM the commenter |
story_leads | IG | Capture leads from story replies |
follower_growth | IG | Contest flow — comment keyword triggers public reply + DM with contest rules + optional share mechanic |
follow_to_dm | IG | Welcome 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=30dReturns 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.