POSTCreate a sequence/api/v1/sequencesGETList sequences/api/v1/sequencesGETGet a sequence/api/v1/sequences/{sequenceId}PATCHRename, activate or pause/api/v1/sequences/{sequenceId}DELETEDelete a sequence/api/v1/sequences/{sequenceId}GETWho is walking it/api/v1/sequences/{sequenceId}/enrollmentsGETList versions/api/v1/sequences/{sequenceId}/versionsPOSTOpen a draft version/api/v1/sequences/{sequenceId}/versionsPATCHChange a draft's trigger/api/v1/sequences/{sequenceId}/versions/{versionId}POSTPublish a version/api/v1/sequences/{sequenceId}/versions/{versionId}/publishPOSTRoll back to a version/api/v1/sequences/{sequenceId}/versions/{versionId}/rollbackDELETEDiscard a draft/api/v1/sequences/{sequenceId}/versions/{versionId}POSTAdd a step/api/v1/sequences/{sequenceId}/versions/{versionId}/nodesGETList steps/api/v1/sequences/{sequenceId}/versions/{versionId}/nodesPATCHEdit a step/api/v1/sequences/{sequenceId}/versions/{versionId}/nodes/{nodeId}DELETERemove a step/api/v1/sequences/{sequenceId}/versions/{versionId}/nodes/{nodeId}POSTMove a step/api/v1/sequences/{sequenceId}/versions/{versionId}/nodes/{nodeId}/moveGETList wires/api/v1/sequences/{sequenceId}/versions/{versionId}/edgesPOSTWire two steps/api/v1/sequences/{sequenceId}/versions/{versionId}/edgesDELETEUnwire two steps/api/v1/sequences/{sequenceId}/versions/{versionId}/edges/{edgeId}
The four things you manipulate
| Object | What it is |
|---|---|
| Sequence | The journey's identity: a name, a status (active / paused), and a pointer to the version currently running |
| Version | A snapshot of the journey, with its trigger. A draft is editable; a published one never changes again |
| Node | One step of a version: send_email, wait, add_tag, remove_tag, end_sequence, webhook |
| Edge | A wire from one node to the next. Adding a node wires it for you; edges exist so you can rewire |
- You never edit a running journey. Editing means opening a draft version, changing it, and publishing it. Contacts already walking the old version finish on the old version.
- The trigger lives on the version, not on the sequence. You set it when you create the
sequence — that call creates version 1 with it — and you change it the way you change anything
else: on a draft, with
PATCHon the version, then publish.
There is no endpoint to enrol a contact directly. Contacts enter a sequence through its
trigger, and only through it: entering a list (
list_joined) or receiving a tag (tag_added).
Use the Audience API to add a contact to the list, or to tag it, and enrolment
follows.Status codes that matter here
Everything on the API reference applies. Three cases come up far more often here:| Status | When |
|---|---|
201 | A sequence, a version, a node or an edge was created |
400 | The journey refuses what you asked — an invalid graph at publish time, a write on a published version, a plan limit |
404 | Unknown id, an id belonging to another organization, or an id belonging to another version |
versionId that is not a version of the sequenceId in
the URL answers 404, and so does a nodeId that is not in that version. Ids are only ever read
inside the path that leads to them.
What a refused publication means
Every defect answers400, names itself, and names the nodes involved — all of them at once,
so you fix in one pass instead of publishing again to discover the next one.
| Defect | What it means | How to fix it |
|---|---|---|
| empty | The version has no node at all | Add at least one node |
| no entry | Every node has something pointing at it — there is no way in | Remove the wire that closes the loop at the top |
| multiple entries | Two nodes have nothing pointing at them | Wire one behind the other; a journey has one door |
| cycle | The wires come back on themselves — a contact would loop forever | Remove the wire that goes backwards |
| orphan | A node is unreachable from the entry | Wire it in, or delete it |
| dangling branch | A branch leads nowhere | Wire its end, or drop the branch |
| ambiguous branch | A node has two outgoing wires with no way to choose | Keep one wire |
| edge out of graph | A wire points at a node of another version | Delete that wire and rewire inside this version |
| empty send | A send_email node has no subject or no content | PATCH the node with a subject and HTML |
| incomplete action | An add_tag / remove_tag node has no tag | PATCH the node with a tagId |
| end with successor | An end_sequence node has a node after it | Delete what follows: nothing runs after the end |
| invalid webhook | A webhook node has no URL, or one the policy refuses | PATCH the node with an https:// public URL |
400 too: a published version is a snapshot, republishing
it in place would rewrite what contacts are walking. Use rollback instead.
Edges
Adding a node wires it for you. These endpoints exist for the shapes an append cannot make — and for undoing one.Writing on a published version
Every write above — adding, editing, deleting, moving a node, wiring, unwiring, changing the trigger — answers400 if the version is not a draft. That is not a permission problem, and
retrying will not help: published versions are snapshots that contacts are executing.
The way through is always the same three calls: open a draft, edit it, publish it.
An onboarding sequence, end to end
1
Create the sequence on its trigger
bash
SEQUENCE_ID=$(curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"name":"Onboarding","triggerType":"list_joined","triggerTargetId":"'$LIST_ID'"}' \
"https://www.agentsmail.io/api/v1/sequences" | jq -r '.data.id')paused, and version 1 already exists as a draft.2
Find the draft to edit
bash
VERSION_ID=$(curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions" \
| jq -r '.data[] | select(.status=="draft") | .id')3
Add the steps, in order
bash
curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"type":"send_email","templateId":"'$TEMPLATE_ID'"}' \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions/$VERSION_ID/nodes"
curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"type":"wait","waitHours":48}' \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions/$VERSION_ID/nodes"
curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"type":"add_tag","tagId":"'$TAG_ID'"}' \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions/$VERSION_ID/nodes"4
Read the graph back
bash
curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions/$VERSION_ID/nodes" \
| jq '.data[] | {id, type, subject, waitHours, tagId}'subject on a send_email is what will be refused at publication. Fix it with
PATCH on the node.5
Publish
bash
curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions/$VERSION_ID/publish"400 here names the defect and the nodes: fix them and publish again. This loop costs
nothing — nothing has been enrolled yet.6
Activate
bash
curl -s -X PATCH -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"status":"active"}' \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID"400.7
Change something later
bash
NEW_VERSION_ID=$(curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" \
"https://www.agentsmail.io/api/v1/sequences/$SEQUENCE_ID/versions" | jq -r '.data.id')