Skip to content

Email sequences ​

A sequence sends a series of templates after a trigger event. It has a draft you edit, published versions, and an isActive switch. Enrollment happens only while the sequence is enabled and has a published version. The Node.js client @funnelsgrove/emails and the fgrove email sequence CLI call these endpoints; see Send lifecycle emails for the workflow.

Every endpoint below takes projectId as a query parameter with an API key.

json
{
  "id": "<sequence-id>",
  "slug": "lead-follow-up",
  "name": "Lead follow-up",
  "currentPublishedVersionId": null,
  "isActive": false,
  "draft": {
    "triggerEventType": "email_captured",
    "funnelIds": [],
    "steps": [{
      "key": "welcome",
      "mode": "template",
      "templateVersionId": "<template-version-id>",
      "variables": { "firstName": "first_name" },
      "personalizationEnabled": false,
      "delaySeconds": 0
    }],
    "exitEventTypes": ["purchase_completed"],
    "lifecycleConsentRequired": true,
    "unsubscribeEnabled": true
  }
}

Draft fields ​

FieldRequiredPurpose
triggerEventTypeYesemail_captured, purchase_completed, registration_completed or payment_upcoming.
funnelIdsNoUp to 50 funnel UUIDs. Empty (the default) means every funnel in the project.
stepsYes1 to 50 steps, in sending order.
exitEventTypesNoEvents that stop the sequence for a user: purchase_completed and/or registration_completed. Default ["purchase_completed"].
lifecycleConsentRequiredNoRequire a current lifecycle marketing opt-in. Default true. Set false only when you have another valid basis for the messages; it does not bypass unsubscribe, bounce, complaint or manual suppression.
unsubscribeEnabledNoKeep the unsubscribe link. Default true.

Step fields ​

FieldRequiredPurpose
keyYesLowercase letters, digits and hyphens, up to 64 characters; unique in the sequence.
delayYes{ "value": <0..2160>, "unit": "hours" | "days" }. The first step waits from the trigger, later steps from the preceding send. Maximum 90 days.
modeNotemplate (default) or direct.
templateTemplate modeSlug of a published template. The draft pins the current published version when it is created or updated.
variablesTemplate modeBinds each declared template variable to a lifecycle value.
personalizationEnabledTemplate modetrue requests an email.personalization_requested webhook 20 minutes before the step sends. Default false.
subject, bodyDirect modeAuthored copy for a direct step.

Direct steps

Direct-copy steps are accepted by the API but cannot yet persist a lifecycle delivery. Do not publish direct steps until that implementation defect is fixed.

payment_upcoming sequences follow extra rules: exactly one template step, a delay (lead time before the charge) from 1 hour to 45 days, no personalization and no exit events. See Upcoming renewal reminder.

Published versions also carry the resolved sender (domainId, domain, fromLocalPart, displayName).

List sequences ​

Scope: email_sequences:read

Request ​

http
GET /email/sequences

Example ​

sh
curl "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences" \
  -H "Authorization: Bearer <project-sdk-secret-key>"

Response ​

A JSON array of sequences.

Get sequence ​

Scope: email_sequences:read

Request ​

http
GET /email/sequences/:sequenceId

Example ​

sh
curl "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>" \
  -H "Authorization: Bearer <project-sdk-secret-key>"

Response ​

json
{
  "sequence": { "id": "<sequence-id>", "slug": "lead-follow-up", "…": "…" },
  "versions": [{ "id": "<version-id>", "sequenceId": "<sequence-id>", "version": 1, "sender": { "…": "…" }, "publishedAt": "…", "…": "…" }]
}

Errors ​

StatusMeaning
400sequenceId is not a UUID.
404The sequence does not exist in this project.

Create sequence ​

Scope: email_sequences:write

Request ​

http
POST /email/sequences
Content-Type: application/json

Parameters ​

FieldRequiredPurpose
slugYesLowercase letters, digits and hyphens, up to 80 characters.
nameYesDisplay name, up to 120 characters.
draftYesThe draft fields.

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences" \
  -H "Authorization: Bearer <project-sdk-secret-key>" \
  -H "Content-Type: application/json" \
  --data '{
    "slug": "lead-follow-up",
    "name": "Lead follow-up",
    "draft": {
      "triggerEventType": "email_captured",
      "funnelIds": [],
      "steps": [
        { "key": "welcome", "template": "welcome", "variables": { "firstName": "first_name" }, "delay": { "value": 0, "unit": "hours" } },
        { "key": "reminder", "template": "reminder", "variables": { "firstName": "first_name" }, "delay": { "value": 2, "unit": "days" } }
      ],
      "exitEventTypes": ["purchase_completed"]
    }
  }'

Response ​

201 with the sequence.

Errors ​

StatusMeaning
400The body is invalid, or a step references a template that is not published.
409A sequence with this slug already exists.

Update sequence ​

Replaces the whole draft.

Scope: email_sequences:write

Request ​

http
PATCH /email/sequences/:sequenceId
Content-Type: application/json

Parameters ​

FieldRequiredPurpose
nameNoNew display name.
draftYesThe complete draft.

Example ​

sh
curl -X PATCH "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>" \
  -H "Authorization: Bearer <project-sdk-secret-key>" \
  -H "Content-Type: application/json" \
  --data '{ "draft": { "triggerEventType": "email_captured", "steps": [ { "key": "welcome", "template": "welcome", "delay": { "value": 1, "unit": "hours" } } ] } }'

Response ​

The updated sequence.

Errors ​

StatusMeaning
400The draft is invalid or references an unpublished template.
404The sequence does not exist in this project.

Add step ​

Appends one step to the draft.

Scope: email_sequences:write

Request ​

http
POST /email/sequences/:sequenceId/steps
Content-Type: application/json

Parameters ​

The step fields.

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>/steps" \
  -H "Authorization: Bearer <project-sdk-secret-key>" \
  -H "Content-Type: application/json" \
  --data '{ "key": "last-call", "template": "last-call", "variables": { "firstName": "first_name" }, "delay": { "value": 48, "unit": "hours" } }'

Response ​

The updated sequence.

Errors ​

StatusMeaning
400The step is invalid or references an unpublished template.
404The sequence does not exist in this project.

Validate sequence ​

Checks that every referenced template is still published.

Scope: email_sequences:read

Request ​

http
POST /email/sequences/:sequenceId/validate

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>/validate" \
  -H "Authorization: Bearer <project-sdk-secret-key>"

Response ​

json
{ "valid": true }

Errors ​

StatusMeaning
400The draft is invalid.
404The sequence does not exist in this project.

Publish sequence ​

Publishes the draft as a new version. Enrollments created afterwards use it.

Scope: email_sequences:write

Request ​

http
POST /email/sequences/:sequenceId/publish

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>/publish" \
  -H "Authorization: Bearer <project-sdk-secret-key>"

Response ​

json
{
  "sequence": { "id": "<sequence-id>", "currentPublishedVersionId": "<version-id>", "…": "…" },
  "version": { "id": "<version-id>", "version": 1, "sender": { "…": "…" }, "publishedAt": "…", "…": "…" }
}

Errors ​

StatusMeaning
400The draft is invalid.
404The sequence does not exist in this project.
409The draft changed while publishing; read it again and retry.

Enable or disable sequence ​

Enabling starts new enrollments; it requires a published version and a sending domain with a valid DMARC policy. Disabling stops new enrollments, and queued steps fail their pre-send check.

Scope: email_sequences:write

Request ​

http
POST /email/sequences/:sequenceId/enable
POST /email/sequences/:sequenceId/disable

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>/enable" \
  -H "Authorization: Bearer <project-sdk-secret-key>"

Response ​

The sequence with its new isActive value.

Errors ​

StatusMeaning
400The sequence cannot be enabled; the message names the problem.
404The sequence does not exist in this project.
409The sequence has no published version.

Cancel an enrollment ​

Cancels the active enrollment of one funnel user in one sequence. Idempotent: the first call returns how many active enrollments were cancelled; a retry after the enrollment is terminal returns cancelled: 0.

Scope: email_sequences:write

Request ​

http
POST /email/sequences/:sequenceId/enrollments/:funnelEndUserId/cancel
Content-Type: application/json

Parameters ​

ParameterInRequiredPurpose
funnelEndUserIdPathYesThe funnel user's user.id from the funnel user bundle.
reasonBodyNoUp to 120 characters, for your records. Default manual.

Example ​

sh
curl -X POST "https://sdk-api.funnelsgrove.com/integration/v1/email/sequences/<sequence-id>/enrollments/<funnel-end-user-id>/cancel" \
  -H "Authorization: Bearer <project-sdk-secret-key>" \
  -H "Content-Type: application/json" \
  --data '{ "reason": "customer_request" }'

Response ​

json
{ "sequenceId": "<sequence-id>", "funnelEndUserId": "<funnel-end-user-id>", "cancelled": 1 }

Cancelling prevents later lifecycle sends, including queued deliveries that have not passed their pre-send check. It cannot recall an email the provider has already started sending.

Errors ​

StatusMeaning
400An ID is not a UUID or reason is invalid.
404The sequence does not exist in this project.

Build. Launch. Grow.