# Flows API reference

Manage flow definitions, nested nodes, branching, and draft lifecycle through the public REST API.

Available on the Scale and Pro plans.

Use flows to define the sequence of questions, offers, branches, and actions shown by a widget or hosted page. Creating a flow does not attach it to a widget or publish it.

## Authentication and flow operations

Paths below follow `https://api.rightmessage.com/v1/{teamPid}`. GET requires `read` or `write`; mutations require `write`. The `*` ability satisfies both. The [shared request conventions](https://rightmessage.com/help/rest-api-overview#base-url-and-authentication) cover bearer authentication, headers, project access, and rate limits.

| Method and path              | Request                             | Success                    |
| ---------------------------- | ----------------------------------- | -------------------------- |
| GET `/flows`                 | No filters or pagination parameters | 200, `{"data":[RESOURCE]}` |
| GET `/flows/{flow}`          | Resource ID from the list           | 200, `{"data":RESOURCE}`   |
| POST `/flows`                | Create body below                   | 201, `{"data":RESOURCE}`   |
| PUT or PATCH `/flows/{flow}` | Partial body below                  | 200, `{"data":RESOURCE}`   |
| DELETE `/flows/{flow}`       | No body                             | 204, empty body            |

PUT and PATCH have the same partial-update behavior. An omitted top-level field retains its value. A collection with no resources returns `{"data":[]}`. Reads return the draft when one exists, otherwise the stable configuration.

## Errors and draft effects

The [shared error contract](https://rightmessage.com/help/rest-api-overview#error-contract) applies. Invalid request fields return 422 with `message` and field-keyed `errors`. Full-configuration validation can return 500 instead.

Mutations save a draft, not live changes. [Publishing](https://rightmessage.com/help/rest-api-publishing) applies the whole project draft, including edits made elsewhere. The [draft contract](https://rightmessage.com/help/rest-api-overview#draft-and-live-configuration) covers snapshots, dashboard updates, and save failures.

## Flow request and response fields

`name` is required on create and optional on update. It is a nonempty string with a maximum of 255 characters. `definition` is an optional object. When omitted on create, it defaults to `{"type":"root","child":[]}`.

A root definition requires `type: "root"` and a `child` array of nodes. It accepts an optional string `_uuid`. No other root properties are allowed. The service generates missing node UUIDs. A supplied definition replaces the complete stored definition, including every branch. It is not a node-level patch.

The resource contains exactly `id`, `name`, and `definition`. Flow IDs use `ofn_`.

## Node schema

Every node has its listed `type` and an optional string `_uuid`, generated when absent. Except for data-action objects, node objects reject undeclared fields. A node run is an ordered array of these nodes.

| Type        | Fields, defaults, and nesting                                                                                                                                                                                                                                                                                                                                                               |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sg`        | Optional nullable `segmentGroupId` identifying a `dim_` group or `raq_` question. Boolean `ask` defaults true. `split` defaults false, or is an array of objects requiring nullable `segmentId` and a `child` node run. Branch objects allow no extra fields.                                                                                                                               |
| `offer`     | Optional nullable `offerId` identifying an `ofr_` offer or form. Optional `desiredType` is `form` or `offer`.                                                                                                                                                                                                                                                                               |
| `yesno`     | Optional string `note`; `condition` logic object, default {}; `yes` and `no` node runs, each default \[].                                                                                                                                                                                                                                                                                   |
| `random`    | Required `split` array. Each branch contains only a required `child` node run.                                                                                                                                                                                                                                                                                                              |
| `highscore` | Required `split` array of objects requiring `score`, a string or null fallback, and `child`. Optional `mode` is `scores` or `variables`; optional `inverse` is boolean.                                                                                                                                                                                                                     |
| `redirect`  | Required string `url`. Boolean `open` defaults false. Boolean `sendSubscriberData` defaults false.                                                                                                                                                                                                                                                                                          |
| `data`      | `actions` array defaults \[]. Each action requires `type` and an `act_` string `id`, generated if absent. Types are `score`, `field`, `variable`, `add_tag`, `remove_tag`, and `set_segment`. Actions accept extra action-specific fields. Declared optional strings are `tagId`, `segmentGroupId`, and `segmentId`. For `set_segment`, a known segment supplies its group ID when omitted. |
| `message`   | Required string `content`.                                                                                                                                                                                                                                                                                                                                                                  |
| `code`      | Required strings `name` and `code`; optional string `selector`.                                                                                                                                                                                                                                                                                                                             |
| `webhook`   | Required string `url` beginning with `https://`. Optional string `name`; `method` is POST, PUT, or PATCH, default POST; string `customPayload` defaults empty; boolean `fireOnce` defaults true; numeric `timeoutMs` defaults 10000; optional boolean `includeVisitorContext`. The schema declares no timeout range.                                                                        |
| `embed`     | Senja embed with `app`, `content`, and `target`, detailed below.                                                                                                                                                                                                                                                                                                                            |
| `exit`      | No fields beyond type and UUID.                                                                                                                                                                                                                                                                                                                                                             |

The REST request checks nonempty `sg.segmentGroupId` and `offer.offerId` references against the current project. These checks recurse through `child`, `split[].child`, `yes`, and `no`. They do not establish a universal referential-integrity guarantee for every action key.

### Data-action runtime fields

The action object is open, but that does not mean arbitrary keys produce a visitor action. Supply the names the runtime reads:

| Action type             | Runtime fields                                                                                                                                                                                                                                                                   |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `score`                 | `score`, the score name; numeric `adjust`, the amount to add                                                                                                                                                                                                                     |
| `field`                 | `field`, the connected provider's field identifier; string `value`, parsed as a Liquid template                                                                                                                                                                                  |
| `variable`              | `variableName` and string `variableValue`, parsed as Liquid. Empty output removes the variable. Optional `expiresType: "duration"` uses a positive `expiresDuration` and `expiresUnit` of minutes, hours, days, or weeks; without duration expiry it stores no expiry timestamp. |
| `add_tag`, `remove_tag` | `tagId`, the provider tag ID                                                                                                                                                                                                                                                     |
| `set_segment`           | `segmentGroupId` and `segmentId`                                                                                                                                                                                                                                                 |

Provider actions require a connected runtime integration. Tag actions can be queued until the visitor is identified; saving the flow does not perform those provider writes. `set_segment` records the chosen answer, clears other answers in that group, refreshes visitor segmentation, and requests active synchronization when the visitor reaches it. The REST schema does not validate every one of these runtime fields, so a successful save alone does not establish that an incomplete action will run.

### Embed nodes

`app` defaults to `senja`, the only schema-supported value. `content` defaults null. A non-null content object must match one of these closed shapes:

- Widget: `kind: "widget"`, nonblank string `id`, string `name`, and string `design`.
- Wall of Love: `kind: "wall_of_love"`, nonblank string `slug`, nonblank string `permalink`, and string `name`.

`target` is either a closed element object requiring `kind: "element"`, string `selector`, `position` of `inside`, `before`, or `after`, and a `pages` logic object; or a closed page object requiring `kind: "page"` and `pages`.

An omitted target defaults to `{"kind":"element","selector":"","position":"after","pages":{"and":[]}}`. New or changed embeds require a registered embed app connected to this project. Unchanged saved embeds do not fail solely because that app was disconnected later. Content is a public resource snapshot, never provider credentials.

### Logic objects

Logic objects can contain recursive `and` and `or` arrays or a `not` object. Answer conditions use the [question condition contract](https://rightmessage.com/help/rest-api-questions#answer-condition-operators). Other stored condition fields pass through this open logic schema. Preserve the returned condition representation rather than inventing another rule syntax.

## Failure and deletion behavior

Unknown question, group, or offer references produce a 422 field error such as `definition.child.0.segmentGroupId`. Invalid node shapes, an HTTP webhook URL, an unknown embed app, or a disconnected app can instead produce 500 through the service exception path. The request's shallow array rules are not the complete schema.

Deleting a flow clears the flow reference from widgets that use it. It does not delete those widgets or their recorded analytics. Creating or updating a flow does not start a resource split test. All site behavior still depends on [publishing the project](https://rightmessage.com/help/rest-api-publishing).

## Illustrative requests and responses

These illustrative examples use the fictional WorkForge project. The same resource schema covers every CRUD response.

```http
GET /v1/123456/flows HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

GET /v1/123456/flows/ofn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

POST /v1/123456/flows HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge welcome",
	"definition": {
		"type": "root",
		"child": [
			{
				"type": "message",
				"content": "Welcome to WorkForge."
			}
		]
	}
}

PATCH /v1/123456/flows/ofn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge updated"
}

DELETE /v1/123456/flows/ofn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
```

The PATCH example also works with PUT. The create, item-read, and update envelopes have this shape. The list places these resource objects in its `data` array. An update returns the updated values. DELETE returns no JSON.

```json
{
	"data": {
		"id": "ofn_example1",
		"name": "WorkForge welcome",
		"definition": {
			"type": "root",
			"_uuid": "11111111-1111-4111-8111-111111111111",
			"child": [
				{
					"type": "message",
					"_uuid": "22222222-2222-4222-8222-222222222222",
					"content": "Welcome to WorkForge."
				}
			]
		}
	}
}
```
