> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequenzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sequence Definitions

> Read and push a whole sequence as one document addressed by your own keys

A sequence definition is one document with a sequence's settings, trigger and steps, addressed by keys you choose. See [Sequences as Code](https://docs.sequenzy.com/concepts/sequences-as-code.md) for the workflow, every step and condition shorthand, and a full example.

Definitions come in two formats, and both work for pushes:

* **Readable** (the default for pulls): a `trigger`, then `steps` in the order they run. Branch and split paths nest their own steps and rejoin at the next step, and the end is implicit.
* **Explicit**: every step with its `type` and `config`, plus a `connections` list. A document with `connections` is read in this format. It describes any sequence.

## Endpoints

* `GET /api/v1/sequences/definitions/{key}` returns the definition of the sequence with that key.
* `PUT /api/v1/sequences/definitions/{key}` creates or updates that sequence from a definition.
* `GET /api/v1/sequences/{sequenceId}/definition` returns any sequence as a definition, including one without a key. Its `key` is an empty string; set one and push to adopt the sequence.

Pulls return the readable format unless you pass `format=raw`. A sequence whose paths cannot be described by nesting is returned in the explicit format either way; the response's `format` says which one you got.

Reads need the `sequences:read` scope and pushes need `sequences:write`, dry runs included.

## Pull a definition

```bash theme={null}
curl "https://api.sequenzy.com/api/v1/sequences/definitions/onboarding" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```json theme={null}
{
  "success": true,
  "format": "readable",
  "definition": {
    "key": "onboarding",
    "id": "seq_abc123",
    "name": "Onboarding",
    "description": null,
    "status": "active",
    "settings": {
      "enrollmentMode": "one_time",
      "enrollmentFieldPath": null,
      "userCancellable": true,
      "activeSubscribersOnly": false,
      "frequencyCapEnabled": true,
      "sendingWindow": null,
      "stopCondition": { "type": "has_tag", "value": "customer", "matchConfig": null },
      "bccEmails": null,
      "senderProfileId": null,
      "replyProfileId": null
    },
    "trigger": { "event": "user.signed_up" },
    "steps": [
      {
        "key": "welcome",
        "email": {
          "name": "Onboarding - welcome",
          "subject": "Welcome",
          "previewText": null,
          "blocks": [{ "id": "blk_1", "type": "text", "variant": "html", "content": "<p>Hi</p>" }]
        }
      },
      { "key": "wait-2d", "wait": "2d" },
      {
        "key": "activated",
        "branch": [{ "if": { "event": "project.created" }, "steps": [{ "key": "mark-active", "tag": "activated" }] }],
        "else": []
      }
    ]
  }
}
```

With `format=raw`, `definition` has `steps` with `type` and `config` for every step, including the trigger and the end step, and a `connections` list of `{ "from", "to", "condition" }`.

Steps that never had a key get one based on their content, such as `welcome` for an email with that subject or `wait-2d`; pushing the document saves those keys on the existing steps. `status` is informational: pushes accept it and ignore it. `managedBy` is left out, so pushing a pulled document never changes who manages the sequence; the sequence list and detail endpoints return it. Webhook header values come back as `[REDACTED]`.

## Push a definition

```bash theme={null}
curl -X PUT "https://api.sequenzy.com/api/v1/sequences/definitions/onboarding?dryRun=true" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @onboarding.json
```

### Query parameters

| Parameter | Description |
| - | - |
| `format` | Pulls only. `raw` returns the explicit format. |
| `dryRun` | `true` returns the changes without saving them. |
| `confirmLiveChange` | `true` is required when the push changes an active sequence. |

### Body

| Field | Description |
| - | - |
| `name` | Required. Up to 255 characters. |
| `key` | Optional; must match the URL key when present. |
| `id` | Optional. When no sequence has the key yet, adopts the sequence with this ID if it has no key. |
| `description` | Optional string or `null`. |
| `managedBy` | `code` or `dashboard`. New sequences default to `code`; an existing sequence keeps its value when omitted. Marketer personal keys cannot change it on an existing sequence. |
| `settings` | Optional. Each omitted field keeps its stored value. `senderProfileId` and `replyProfileId` must belong to your company. |
| `trigger` | Readable format: required. `event` (with optional `where`), `tag`, `list`, `segment`, `manual: true`, or `type` and `config`. Optional `key` (default `trigger`) and `label`. |
| `steps` | Required, up to 200 steps in all. Each has a unique `key`. Readable steps take one of `wait`, `email`, `branch` (with `else`), `split`, `continueIf`, `tag`, `untag`, `end: true`, or `type` and `config`, plus optional `label`, `config` and `next`. Explicit steps take a `type` and a `config`. |
| `connections` | Explicit format: `from` and `to` step keys, and an optional `condition` for branch lanes. Replaces the stored connections. Leave it out to use the readable format. |

An `email` has `subject` (up to 500 characters), optional `name` (255) and `previewText` (255), and either `blocks` or `html`, or a `template` with the ID of an email in your company. A template supplies the subject, preview text, content and style for any of those the step does not write, and the step keeps its own copy, refreshed from the template on every push. `email` is required for a new email step, and a new email needs a subject or a template; omit `email` to keep the stored content, and omit `name` or `previewText` to keep those.

Unknown fields are rejected, and readable-format errors name the place in the document, such as `steps[2].branch[0].if: unknown condition`. Unknown config fields are ignored and reported in `warnings`; config values of the wrong type are rejected.

### How the push applies

* Steps are matched by key. New keys are added, changed steps are updated in place and missing steps are removed.
* Contacts waiting on a removed step continue to the step that follows it, or complete when nothing follows. If contacts are waiting and the removed step could lead to more than one surviving step, the push returns `400`.
* A/B test steps keep their stored settings; a push cannot create or remove them. Inbound webhook triggers keep their key and config (only the label can change), and a trigger cannot switch to or from an inbound webhook.
* The connections must keep exactly one trigger, reach an end step from every step and contain no cycles.
* The push never changes `status` or the enrollment pause. New sequences are created as drafts.
* The sequence changes in one transaction: on any error it is left as it was. Tag and event definitions the document names may be created before that.

### Response

```json theme={null}
{
  "success": true,
  "dryRun": true,
  "created": false,
  "hasChanges": true,
  "sequence": {
    "id": "seq_abc123",
    "key": "onboarding",
    "name": "Onboarding",
    "status": "active",
    "managedBy": "code"
  },
  "changes": {
    "sequence": ["settings.sendingWindow"],
    "steps": {
      "added": ["reminder"],
      "changed": [{ "key": "welcome", "fields": ["email.subject"] }],
      "removed": [
        { "key": "wait-1d", "type": "logic_delay", "contacts": 3, "contactsContinueTo": "welcome" }
      ]
    },
    "connections": {
      "added": [{ "from": "welcome", "to": "reminder" }],
      "removed": [{ "from": "wait-1d", "to": "welcome" }]
    }
  }
}
```

A push that creates the sequence returns `201`. A push identical to what is stored returns `200` with `hasChanges: false` and writes nothing.

### Errors

| Status | When |
| - | - |
| `400` | The document is invalid: an unknown field, a readable step or condition that cannot be read, a `template` that was not found, a duplicate step key, a connection to a missing step, a broken graph, a step whose type changed, a new or removed A/B test step, a changed inbound webhook trigger, an `{{event.*}}` attachment without an event trigger, a value over its length limit, a profile from another company, or a removed step whose waiting contacts have more than one place to go. Also returned, with the `changes`, when an active sequence is pushed without `confirmLiveChange=true`. |
| `401` | Missing or invalid API key. |
| `404` | The key belongs to a sequence your role cannot see, or the `id` to adopt was not found. |
| `409` | The sequence changed while the push was prepared, a contact was being processed on a removed step, or another push took the key at the same time. Push again. |

Retrying a push is safe: the same document applied twice ends in the same sequence.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.