# Flow templates

GET /flow/templates returns the ready-made flows worth offering a project, scored against the events it really receives. This page covers relevance and scoring, the SMS and RCS modes, the language of the messages, the integration filter, and how to create a flow from a template.

**Language:** en
**Audience:** developer
**TLDR:** GET /v1/project/{project}/flow/templates lists ready-made flows scored for this project, each with a payload that validates once a sender is set. relevance is received (the trigger event arrived in the last 14 days), available (a connected source can send it) or unavailable. channel=rcs builds every send as RCS with the same SMS as fallback. Messages follow the project's language; lang only translates titles. Create one with POST /flow, passing the payload as draft and the key as template.
**Search keywords:** flow template, flow templates, template gallery, ready-made flow, prebuilt flow, flow recipe, recommended flows, abandoned checkout, abandoned cart, cart recovery, welcome flow, winback, win-back, review request, thank you, relevance, received, available, unavailable, score, scoring, recommended, used, payload, channel rcs, rcs fallback, sms fallback, lang, language, translation, localizations, integration filter, shopify, create from template
**Related pages:** /developers/product-api/flows/overview, /developers/product-api/flows/drafts, /developers/product-api/flows/triggers-and-exits, /platform/en/automations/flows
**Docs index (every page):** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt
**This zone's index:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/llms-full.txt
**This page:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/flows/templates/ (HTML) · https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/flows/templates.md (Markdown)

Writing a flow graph from nothing is the slowest and most error-prone way to build one. The template list is the shortcut: a catalogue of ready-made journeys (an abandoned-checkout reminder, a welcome, a winback and others), each **scored for this particular project** against the events it actually receives, and each carrying a complete graph with the trigger event and its source already chosen.

The intended path is to take the payload of the closest template, change only what you need, and create the flow from it.

The dashboard shows the same list as its template gallery, with the same recommendations; how customers use it is described in [Flows → Templates](/platform/en/automations/flows#templates).

[`GET /v1/project/{project}/flow/templates` - List the flow templates worth offering this project.](/developers/product-api/reference)

The endpoint takes the `PROJECT_AUTOMATION_READ` scope and sits in the **medium** [rate-limit](/developers/product-api/rate-limits) class.

## Query parameters

- `lang` — `string`, default: `en`
  `en` or `es`. The language of each template's `title` and `description`. It does **not** change the language of the messages, which follow the project's own language (see [Message language](#message-language)).
- `channel` — `string`, default: `sms`
  `sms` or `rcs`: the mode every `payload` is built in. See [SMS or RCS with SMS fallback](#sms-or-rcs-with-sms-fallback).
- `integration` — `string`
  An integration key, such as `shopify`. Keeps only the templates that integration can feed, scored as if it were connected. See [What would an integration unlock](#what-would-an-integration-unlock).

## The response

```json
{
  "entities": [
    {
      "key": "abandoned-checkout",
      "title": "Abandoned checkout",
      "description": "Reminds shoppers who started a checkout and did not buy within 30 minutes. Stops as soon as they order.",
      "categories": ["ecommerce", "checkout_abandoned"],
      "icon": "shopping-cart",
      "recommended": true,
      "integrations": [
        { "integration": "shopify", "name": "Shopify", "connected": true }
      ],
      "channels": ["sms", "rcs"],
      "channel": "sms",
      "relevance": "received",
      "trigger": {
        "eventType": "ecommerce_checkout_init",
        "datasourceId": "66c3a1b2e5a6b7c8d9e0f1a2",
        "candidates": ["ecommerce_checkout_init"],
        "lastSeenAt": "2026-09-25T08:41:12+00:00"
      },
      "score": 60,
      "scoring": [
        { "signal": "relevance", "delta": 40, "text": "My Shop sent 412 ecommerce_checkout_init events in the last 30 days" },
        { "signal": "business", "delta": 20, "text": "Suited to ecommerce businesses" }
      ],
      "used": false,
      "payload": { "trigger": { "stepClass": "TRIGGER_CONTACT_EVENT", "eventType": "ecommerce_checkout_init", "...": "..." } }
    }
  ],
  "window": { "days": 30 }
}
```

- `key` — `string`
  The template's stable identifier. Pass it as `template` when you create a flow from it.
- `title` — `string`
  The template's name, in the `lang` you asked for.
- `description` — `string`
  What the journey does, in the `lang` you asked for.
- `categories` — `string[]`
  Free tags for grouping templates in a gallery.
- `icon` — `string`
  A [Lucide](https://lucide.dev) icon name in kebab-case, fixed per template.
- `recommended` — `boolean`
  `true` on at most three templates: the best-scored ones whose trigger event was received and that have not been used yet. The same set the project's [recommendations](/developers/product-api/project-setup/recommendations) surface.
- `integrations` — `object[]`
  The integrations that can send the trigger event, connected first, each with `integration` (its key), `name` and `connected`. Empty for templates triggered by Instasent's own events, which fire whatever the source.
- `channels` — `string[]`
  The send modes this project can use: `sms`, plus `rcs` when the project has an active RCS sender.
- `channel` — `string`
  The mode `payload` was built in, which is the `channel` you asked for.
- `relevance` — `string`
  `received`, `available` or `unavailable`. See [Relevance](#relevance).
- `trigger` — `object`
  The trigger the template resolved to for this project.
  
  - `eventType` — `string`
    The event type the payload triggers on.
  - `datasourceId` — `string`
    The data source the payload's trigger listens to: the event's [preferred source](/developers/product-api/flows/triggers-and-exits#the-event-and-its-source). `null` for Instasent's own events, and when no connected source sends the event yet.
  - `candidates` — `string[]`
    The event types the template can trigger on, in order of preference. The first one this project receives wins.
  - `lastSeenAt` — `string`
    The last time the trigger event arrived inside `window`, whatever `relevance` says. On an `unavailable` template a value means the event is stale — it arrived, but more than 14 days ago — not unknown.
- `datasources` — `object[]`
  The sources that send the trigger event, best first.
- `score` — `integer`
  The template's score for this project. Only templates scoring above zero are listed.
- `scoring` — `object[]`
  One entry per reason behind the score: `signal`, `delta` (points added or removed) and `text`, an English sentence built from the facts above.
- `used` — `boolean`
  `true` while a flow created from this template exists and is not archived.
- `payload` — `object`
  The flow graph, ready to send as the `draft` of [`POST /flow`](/developers/product-api/flows/drafts#creating-a-flow). Its shape is described in [Nodes](/developers/product-api/flows/nodes).

`window.days` is the window the event counts behind relevance and scoring cover. It follows the plan: 30 days on free plans, 180 on paid ones, the same bound the [event volumes probe](/developers/product-api/audience/probes#event-volumes) applies.

## Relevance

Relevance answers the question that decides whether a flow will ever fire: **does the event it triggers on actually arrive in this project?**

| `relevance`   | What it means                                                                                     | What to do                                                          |
| ------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `received`    | A source that can trigger flows sent the trigger event in the last 14 days.                       | The flow fires today. The natural candidate to offer.               |
| `available`   | No such event arrived in the last 14 days, but a connected integration declares that it sends it. | The flow is buildable; it will fire once the events start arriving. |
| `unavailable` | No connected source sends the event, or it last arrived more than 14 days ago.                    | Connecting a source that sends it comes before building the flow.   |

Relevance is **data first**. The events a project really receives outweigh the business type it declared, so a project that sells online while describing itself otherwise still sees the ecommerce journeys, as long as its orders arrive.

When a template can trigger on more than one event (a review request can follow a delivery or, failing that, a shipment), the first candidate the project receives is the one the payload uses, and a `scoring` sentence says so. A trigger filter in the graph follows the event it was rewritten to.

## Scoring and order

`score` is the sum of the `delta` of every `scoring` entry. The signals include the trigger's relevance (a received event weighs most), extra sources that also send it, how well the template suits the project's business type, whether the trigger is the project's own sales conversion event, and whether a complementary or overlapping flow already exists. Each entry says in plain words what it measured, so the list can be shown to a person, or read by a model, as the reason a template is on offer.

Templates are ordered with `used` ones last, then by score. Treat the weights as the platform's judgement, not a contract: read `scoring` rather than recomputing it.

## SMS or RCS with SMS fallback

Templates are authored as SMS. `channel=rcs` rebuilds every send in the payload as a **plain-text RCS message** with the same SMS, unchanged, as its [fallback](/developers/product-api/flows/nodes#fallback) for contacts RCS cannot reach. The consent policy is the same on both levels. There is no RCS-only mode.

- `rcs` is accepted only when the template's `channels` lists it, which means the project has an active RCS sender; otherwise the request is a `400`.
- The mode is **never chosen for you**. RCS messages are billed as RCS, so offer it as an option to the person who will publish the flow rather than switching to it on their behalf.

## Message language

The messages in `payload` are written in the **project's language**: Spanish for a Spanish project, English otherwise. `lang` only translates `title` and `description`.

When the organization's plan allows multi-language messages, every send in the payload also carries the other language as a translation, in the option's `localizations`. At send time each contact receives the translation matching their language, and anyone else receives the default text. See [Translations](/developers/product-api/flows/nodes#translations).

## What the payload leaves to you

A template payload validates as soon as one thing is added: **the sender of each send**. It is never set, on the message or on its translations, because which sender speaks for the brand is the customer's choice. Created without one, the flow is saved with `valid: false` and an error on each send, and it can be completed in the dashboard. See [The send](/developers/product-api/flows/nodes#the-send).

Everything else is already filled in the way the platform recommends:

- The trigger listens to the event's preferred source, and the exits to the same source.
- The audience is restricted to contacts with a mobile phone, so nobody enters a journey that can never send.
- Every marketing send waits in a [smart delay](/developers/product-api/flows/delays#smart-delay) that avoids illegal hours, and every send declares its consent policy.
- A contact is never inside two runs of the same flow at once, and journeys that should happen once (a welcome) or not too often (a checkout reminder) carry their own [re-entry limits](/developers/product-api/flows/triggers-and-exits#re-entry-and-caps).

## Creating a flow from a template

#### 1. List the templates

Call `GET /flow/templates` and pick the item to use: typically a `recommended` one, or the one the user asked for by name.

#### 2. Set the senders

Add the id of a sender from this project to each send in `payload`. Change anything else the user asked for, and nothing more.

#### 3. Create the flow

Send the payload as `draft` and the item's `key` as `template`, so the flow records where it came from and the template is marked `used`.

```bash
curl -X POST "$BASE/flow" \
  -H "Authorization: Bearer $INSTASENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Abandoned checkout",
    "template": "abandoned-checkout",
    "draft": { "trigger": { "stepClass": "TRIGGER_CONTACT_EVENT", "eventType": "ecommerce_checkout_init" } }
  }'
```

The `draft` above is shortened: send the whole `payload`. The response and its errors are in [Creating and editing drafts](/developers/product-api/flows/drafts#creating-a-flow). An unknown `template` key is a `400`.

## What would an integration unlock

`integration=<key>` answers "which journeys would connecting this integration make possible?". It keeps only the templates that integration can feed and scores them as if it were connected:

- If the project **has** connected it, the templates score on its real data.
- If it has **not**, the integration counts as a source that has sent nothing yet, so its templates come back `available` with no `trigger.datasourceId`, unless another source already sends the event.

An unknown integration, or one that cannot trigger flows, is a `400`. Take the keys from the `integrations` of the items.

## Errors

| Status                     | When                                                                                                                                                     |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`                      | `channel` is not one the project can use (`rcs` without an active RCS sender, or an unknown value), or `integration` is unknown or cannot trigger flows. |
| `401`, `403`, `429`, `5xx` | As described in [Errors](/developers/product-api/errors).                                                                                                |

## What's next

- [Creating and editing drafts](/developers/product-api/flows/drafts) - Create the flow from the payload, then read, replace and validate its draft.
- [Triggers and exits](/developers/product-api/flows/triggers-and-exits) - Why the trigger points at one source, and how exits and goals work.

---

This is one page of the Instasent documentation. For the complete machine-readable index of every guide and API reference, fetch https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt — start there for full context.
