---
title: "Flows commands"
description: "Adapty CLI commands that create flows, read and write their builder configs, validate and preview them, upload media, and publish them."
---

> **AI agents**: to search Adapty docs faster and with fewer tokens, install the Adapty skills: `npx adapty skills install --yes`

[Flows](adapty-flow-builder) are the paywalls and onboardings you build in the Flow & Paywall Builder. The CLI manages the flow record, its builder config, and publication. A builder config is a large JSON document that the Flow & Paywall Builder normally produces, and the CLI doesn't generate one. To author or edit a config from the terminal, use the [flow-generator skill](flow-generator-skill), which drives these commands for you. Before publishing, the [flow-audit skill](flow-audit-skill) checks whether the flow is ready for production. The commands are listed here as a reference.

## adapty flows list

List all flows for an app.

```bash
adapty flows list --app <app-id>
```

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |

Accepts [pagination flags](developer-cli-reference#global-flags).

## adapty flows get

Get details for a specific flow.

```bash
adapty flows get --app <app-id> <flow-id>
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |

The response contains `id`, `name`, `status`, and `updated_at`. The status is one of:

| Status | Meaning |
|---|---|
| `draft` | The flow has never been published |
| `published` | The current version is live |
| `dirty` | The flow was published before, and the current version has unpublished changes. Users keep seeing the last published version |
| `publishing` | Publication is in progress |
| `publication_failed` | The last publication failed. Fix the config and publish again |
| `archived` | The flow is archived |

## adapty flows create

Create a flow. The new flow has a name and no config. To add a config, use [`flows config update`](#adapty-flows-config-update).

```bash
adapty flows create --app <app-id> --name "Onboarding"
```

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |
| `--name` | Yes | Flow name |

## adapty flows update

Rename a flow.

```bash
adapty flows update --app <app-id> <flow-id> --name "Onboarding v2"
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |
| `--name` | Yes | New flow name |

## adapty flows publish

Publish the current version of a flow to your users.

```bash
adapty flows publish --app <app-id> <flow-id>
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |
| `--yes`, `-y` | No | Publish without asking for confirmation. Required when the output is piped or `--json` is used |

Because publishing changes what your users see, the command prints the flow name and asks for confirmation. Any answer other than `y` cancels the command with exit code 1. Under `--json` or in a pipe, the command refuses with exit code 2 instead of waiting for an answer, so pass `--yes` in scripts and agent sessions.

Publication is asynchronous: the response reports `status: publishing`, and the flow isn't live yet. Poll [`flows get`](#adapty-flows-get) until the status becomes `published` or `publication_failed`. On `publication_failed`, [`flows config get`](#adapty-flows-config-get) reports why.

Publishing fails with HTTP 400 when the flow has no config, when the config isn't publishable, or when the current version is already live. To check a config before publishing, use [`flows config validate`](#adapty-flows-config-validate).

## adapty flows config get

Read the builder config of a flow.

```bash
adapty flows config get --app <app-id> <flow-id>
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |

The response contains `config`, `remote_configs`, `status`, and `updated_at`. `updated_at` is a millisecond timestamp of the last config change. Pass it to [`flows config update`](#adapty-flows-config-update) as `--expected-updated-at` to avoid overwriting a concurrent edit. A flow whose config has never been written returns 404.

After a publication attempt, the response also carries three fields describing how it went. Read them when [`flows get`](#adapty-flows-get) reports `publication_failed`:

| Field | Description |
|---|---|
| `publication_status` | How far publication of this flow version got: `transforming`, `transformed`, `uploading`, `uploaded`, `published`, or `failed` |
| `transform_error` | The raw transform failure — either a JSON payload listing the issues or a summary string |
| `publication_error` | A readable message for a failed publication |

## adapty flows config update

Write the builder config of a flow.

```bash
adapty flows config update --app <app-id> <flow-id> --config-file config.json
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |
| `--config` | One of the two | Builder config as a JSON string |
| `--config-file` | One of the two | Path to a JSON file with the builder config, or `-` to read from stdin |
| `--remote-configs` | No | JSON array of `{locale, data}` entries, where `data` is the remote config as a string |
| `--expected-updated-at` | No | The `updated_at` value from a prior `flows config get`. If the config changed after that read, the command fails instead of overwriting the change. Omit it to overwrite unconditionally |

Writing the config saves a draft and doesn't publish it. On a published flow, the write creates a new version: the flow's status becomes `dirty`, and users keep seeing the published version until you run [`flows publish`](#adapty-flows-publish).

## adapty flows config validate

Check whether a builder config is publishable, without saving it.

```bash
adapty flows config validate --app <app-id> <flow-id> --config-file config.json
```

| Argument | Description |
|---|---|
| `flow-id` | Flow ID (UUID) |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |
| `--config` | One of the two | Builder config as a JSON string |
| `--config-file` | One of the two | Path to a JSON file with the builder config, or `-` to read from stdin |

The response contains `valid` and a list of `issues`. When the config isn't publishable, the command exits with code 1, so scripts can gate on it.

## adapty flows config preview

Render a local config file in the browser. This command makes no API call and takes no `--app` flag.

```bash
adapty flows config preview ./config.json --screen <screen-id> --device iphone-14 --orientation portrait
```

| Argument | Description |
|---|---|
| `config-file` | Path to a local builder config JSON file |

| Flag | Default | Description |
|---|---|---|
| `--screen` | The flow's first screen | Screen ID to render |
| `--device` | `iphone-14` | Device frame to render in |
| `--orientation` | `portrait` | `portrait` or `landscape` |

In a terminal, the command opens the preview in your browser. When piped or with `--json`, it prints the URL instead. The URL contains the whole config and is long: pipe it into a screenshot tool rather than printing it. Configs over roughly 32 KB render slowly.

## adapty flows media upload

Upload an image to use in a flow config.

```bash
adapty flows media upload --app <app-id> ./hero.png
```

| Argument | Description |
|---|---|
| `file` | Path to the image file |

| Flag | Required | Description |
|---|---|---|
| `--app` | Yes | App ID (UUID) |

Accepted formats: GIF, HEIC, JPEG, PNG, SVG, and WebP. The response contains the image `id`, `name`, and the CDN `url` to reference from the config.

## What's next

- [Command reference](developer-cli-reference) — every CLI topic, the global flags, and the pagination flags.