Flow format and worked examples for agents
The JSON document every flow is made of, the rules the checker enforces, and three complete examples an agent can copy.
Where it is in the app
Open Home, choose Settings, then General › API keys.
- Home
- Settings
- General
- API keys
Every flow, whether a person dragged it together or an agent wrote it, is one JSON document. This page describes it. "Agents and the API" explains how to give an agent a key.
#How a flow gets built
The agent works in five steps, and the guide it reads first says so:
Look at what you have. Your lists, your segments, the events your shop is sending, the emails you have already designed.
Write the emails it needs, or reuse yours.
Compose the flow as one JSON document.
Create it. It arrives switched off.
Ask you to switch it on — or switch it on itself, if you allowed that.
#The flow itself
Every flow in this platform, whether a person dragged it or an agent wrote it, is one JSON document with five fields.
| Field | What it is |
|---|---|
trigger |
What starts it. A list someone joins, an event from your shop, a segment they enter, or a date on the person (birthday, renewal). |
entryFilters |
Who is allowed in. Checked once at the door. Somebody who fails is never enrolled at all. Optional. |
exitConditions |
What ends it early. "They ordered" is the usual one — an abandoned-cart flow must stop the moment the order lands. |
steps |
The work: emails, texts, waits, branches, list changes, team alerts. Every step has an id and points at the next one by id. |
entryStepId |
Which step runs first. |
The rules the checker enforces, and refuses the whole document over:
- Step ids are unique,
entryStepIdnames a real step, and everynextpoints at a real step or isnull(which means "this path ends here"). - A wait is in whole minutes and greater than zero.
- A percentage split has to total exactly 100.
- A branch path needs at least one condition; "everyone else" is the required
otherwise. - A text can be up to 459 characters, and its merge tags have to be balanced.
- A condition that reads an event's payload uses a plain dot path such as
totalorshippingAddress.countryCode. There is no expression language. - A team alert may only go to your own teammates' addresses.
- A web hook may not point at a private address.
- Once a trigger is set it is locked. A live flow is read-only until it is paused.
The machine-readable version of all of this — the full schema, the rules as sentences, and the three examples below — is one request: GET /api/agent/v1/flows/schema, or the flow_schema tool. An agent that reads it builds a valid flow first try.
#Three worked examples
The template and list ids below are zeros. Real ones come from list_templates and list_lists.
A welcome series. Somebody joins a list, gets an email, waits two days, gets another.
{
"trigger": {
"kind": "list_added",
"listId": "00000000-0000-0000-0000-000000000000"
},
"entryStepId": "email-1",
"exitConditions": [],
"steps": [
{
"id": "email-1",
"kind": "send_email",
"templateId": "00000000-0000-0000-0000-000000000000",
"next": "wait-1"
},
{ "id": "wait-1", "kind": "wait", "minutes": 2880, "next": "email-2" },
{
"id": "email-2",
"kind": "send_email",
"templateId": "00000000-0000-0000-0000-000000000000",
"next": "end"
},
{ "id": "end", "kind": "exit" }
]
}An abandoned cart. Started by the shop's checkout event, waits an hour, and only mails the people who still have not ordered. The exit condition is the belt to the branch's braces: it stops the run the instant an order arrives.
{
"trigger": {
"kind": "event",
"name": "checkout_started",
"source": "woocommerce"
},
"entryStepId": "wait-1",
"exitConditions": [{ "event": "order_created" }],
"steps": [
{ "id": "wait-1", "kind": "wait", "minutes": 60, "next": "check" },
{
"id": "check",
"kind": "branch",
"paths": [
{
"name": "still has not ordered",
"when": [
{
"kind": "not_had_event_since_entry",
"name": "order_created"
}
],
"next": "email-1"
}
],
"otherwise": "end"
},
{
"id": "email-1",
"kind": "send_email",
"templateId": "00000000-0000-0000-0000-000000000000",
"next": "end"
},
{ "id": "end", "kind": "exit" }
]
}A birthday text, for people on one list only.
{
"trigger": {
"kind": "date_property",
"attribute": "birthday",
"offsetDays": 0,
"atHour": 9
},
"entryFilters": [
{
"kind": "in_list",
"listId": "00000000-0000-0000-0000-000000000000"
}
],
"entryStepId": "sms-1",
"exitConditions": [],
"steps": [
{
"id": "sms-1",
"kind": "send_sms",
"body": "Happy birthday from all of us. 20% off anything today.",
"next": "end"
},
{ "id": "end", "kind": "exit" }
]
}