Command reference for the Adapty Developer CLI
This article lists the Adapty CLI commands that configure your account — apps, access levels, products, paywalls, flows, placements, and segments — with their arguments, flags, and accepted values. For Apple Ads campaigns, see Ads Manager commands.
For authentication setup and token management, see Authentication.
Global flags
These flags are available on all commands.
| Flag | Description |
|---|---|
--json | Output as JSON instead of formatted text |
--help | Show command help |
All list commands also accept pagination flags:
| Flag | Default | Description |
|---|---|---|
--page | 1 | Page number |
--page-size | 20 | Items per page (max: 100) |
Apps
Manage the apps in your Adapty account. For Dashboard-based configuration, see App settings.
adapty apps list
List all apps in your Adapty account.
adapty apps list
Accepts pagination flags.
adapty apps get
Get details for a specific app.
adapty apps get <app-id>
| Argument | Description |
|---|---|
app-id | App ID (UUID) |
adapty apps create
Create a new app.
adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app
| Flag | Required | Description |
|---|---|---|
--title | Yes | App title |
--platform | Yes | Platform: ios or android. Repeat for both: --platform ios --platform android |
--apple-bundle-id | Required with --platform ios | Apple bundle ID |
--google-bundle-id | Required with --platform android | Google bundle ID |
adapty apps update
Update an existing app.
adapty apps update <app-id> --title "New Name"
| Argument | Description |
|---|---|
app-id | App ID (UUID) |
| Flag | Description |
|---|---|
--title | New app title |
--apple-bundle-id | New Apple bundle ID |
--google-bundle-id | New Google bundle ID |
At least one flag is required. --platform cannot be changed after creation.
Access levels
adapty access-levels list
List all access levels for an app.
adapty access-levels list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
adapty access-levels get
Get details for a specific access level.
adapty access-levels get --app <app-id> <access-level-id>
| Argument | Description |
|---|---|
access-level-id | Access level ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
adapty access-levels create
Create a new access level.
adapty access-levels create --app <app-id> --sdk-id "pro" --title "Pro"
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--sdk-id | Yes | Identifier used in app code to check access (for example, "pro" or "premium") |
--title | Yes | Display label for the Adapty dashboard |
adapty access-levels update
Update an existing access level.
adapty access-levels update --app <app-id> <access-level-id> --title "Pro Access"
| Argument | Description |
|---|---|
access-level-id | Access level ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | New display label |
--sdk-id cannot be changed after creation.
Products
adapty products list
List all products for an app.
adapty products list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
adapty products get
Get details for a specific product.
adapty products get --app <app-id> <product-id>
| Argument | Description |
|---|---|
product-id | Product ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
adapty products create
Create a new product.
The store product and price IDs cannot be changed after creation. To use different store IDs, create a new product.
adapty products create --app <app-id> --title "Monthly" --access-level-id <access-level-id> --period monthly --ios-product-id com.example.monthly
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | Product title |
--access-level-id | Yes | Access level ID (UUID) this product unlocks |
--period | Yes | Subscription period: weekly, monthly, two_months, trimonthly, semiannual, annual, lifetime |
--ios-product-id | At least one store required | Product ID from App Store Connect |
--android-product-id | At least one store required | Product ID from Google Play Console |
--android-base-plan-id | Required with --android-product-id unless --period lifetime | Base plan ID from Google Play Console |
--stripe-product-id | At least one store required | Product ID from Stripe |
--stripe-price-id | Required with --stripe-product-id | Price ID from Stripe |
--paddle-product-id | At least one store required | Product ID from Paddle |
--paddle-price-id | Required with --paddle-product-id | Price ID from Paddle |
Every product needs at least one store: --ios-product-id, --android-product-id, --stripe-product-id, or --paddle-product-id. A single product can carry IDs for several stores at once.
To sell a product on the web through Stripe or Paddle, connect the payment provider to Adapty first: see Stripe and Paddle. For each of these stores, pass the product ID and the price ID together. The command fails if you pass only one of the pair.
adapty products create --app <app-id> --title "Monthly" --access-level-id <access-level-id> --period monthly --stripe-product-id prod_xxx --stripe-price-id price_xxx
A web-only product is valid: you can create a product with Stripe or Paddle IDs and no App Store or Google Play IDs.
adapty products update
Update an existing product.
Store product and price IDs cannot be changed after creation and are not available in this command. To use different store IDs, create a new product.
adapty products update --app <app-id> <product-id> --title "Monthly" --access-level-id <access-level-id>
| Argument | Description |
|---|---|
product-id | Product ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | No | Product title |
--access-level-id | No | Access level ID (UUID) this product unlocks |
Paywalls
adapty paywalls list
List all paywalls for an app.
adapty paywalls list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
adapty paywalls get
Get details for a specific paywall.
adapty paywalls get --app <app-id> <paywall-id>
| Argument | Description |
|---|---|
paywall-id | Paywall ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
adapty paywalls create
Create a new paywall.
adapty paywalls create --app <app-id> --title "Default Paywall" --product-id <product-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | Paywall title |
--product-id | Yes | Product ID (UUID). Repeat for multiple products: --product-id <id1> --product-id <id2> |
adapty paywalls update
Replace all fields of an existing paywall.
Once a paywall is linked to a placement, its products cannot be changed. To use different products in a live paywall, create a new paywall and update the placement to point to it.
adapty paywalls update --app <app-id> <paywall-id> --title "Default Paywall" --product-id <product-id>
This command replaces all paywall fields, including the full product list.
| Argument | Description |
|---|---|
paywall-id | Paywall ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | Paywall title |
--product-id | Yes | Product ID (UUID). Repeat for multiple products: --product-id <id1> --product-id <id2> |
adapty paywalls placements
List all placements that currently use a given paywall.
adapty paywalls placements --app <app-id> <paywall-id>
| Argument | Description |
|---|---|
paywall-id | Paywall ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Use this command before swapping a paywall to see which placements would be affected.
The items in this list carry no is_active field. To read a placement’s activation state, use placements list or placements get.
Flows
Flows 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, which drives these commands for you. Before publishing, the 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.
adapty flows list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
adapty flows get
Get details for a specific flow.
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 create --app <app-id> --name "Onboarding"
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--name | Yes | Flow name |
adapty flows update
Rename a flow.
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.
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 until the status becomes published or publication_failed. On publication_failed, 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 get
Read the builder config of a flow.
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 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 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.
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 config validate
Check whether a builder config is publishable, without saving it.
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.
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.
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.
Placements
Placements are where your flows, paywalls, and onboardings reach users. A placement’s content type is fixed at creation, so moving an app from paywalls to flows means creating new placements rather than updating the existing ones — the migrate-placements skill drives these commands to do that in bulk.
adapty placements list
List all placements for an app.
adapty placements list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
Each item contains id, developer_id, title, and is_active. is_active is true for a live placement and false for an inactive one.
adapty placements get
Get details for a specific placement.
adapty placements get --app <app-id> <placement-id>
| Argument | Description |
|---|---|
placement-id | Placement ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
The response contains id, developer_id, title, is_active, and an audiences array. is_active is true for a live placement and false for an inactive one. Each audience entry carries content_type (paywall or flow), segment_ids, priority, and either paywall_id or flow_id. The default audience has segment_ids: [] and the highest priority value (last evaluated). See Audiences shape.
adapty placements create
Create a new placement.
adapty placements create --app <app-id> --title "Main" --developer-id "main" --audiences '[{"content_type":"paywall","segment_ids":[],"paywall_id":"<paywall-id>","priority":0}]'
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | Placement title |
--developer-id | Yes | String identifier used in app code to request this placement |
--audiences | One of the two | JSON array of audience entries, each with an explicit content_type. See Audiences shape |
--paywall-id | One of the two | Deprecated. Paywall ID (UUID). Wrapped client-side into a single default audience |
Pass exactly one of --audiences or --paywall-id. Passing both or neither errors out.
--paywall-id is deprecated and will be removed. When passed, the CLI prints a stderr warning and converts the value into a default audience. Use --audiences for new automation.
adapty placements update
Replace all fields of an existing placement.
adapty placements update --app <app-id> <placement-id> --title "Main" --developer-id "main" --audiences '[{"content_type":"paywall","segment_ids":[],"paywall_id":"<paywall-id>","priority":0}]'
This command replaces all placement fields, including the full audiences list.
| Argument | Description |
|---|---|
placement-id | Placement ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
--title | Yes | Placement title |
--developer-id | Yes | String identifier used in app code to request this placement |
--audiences | One of the two | JSON array of audience entries, each with an explicit content_type. See Audiences shape |
--paywall-id | One of the two | Deprecated. Paywall ID (UUID). Replaces all audiences with a single default audience |
Passing --paywall-id rewrites all audiences on the placement. Segment-specific audiences are dropped. To preserve them, use --audiences and include all entries you want to keep.
Audiences shape
The --audiences flag takes a JSON array. Each entry has:
| Field | Type | Description |
|---|---|---|
content_type | string | "paywall" or "flow". Required on every entry. All entries in one placement must have the same value |
segment_ids | string[] | Segment IDs targeted by this audience. Length 0 or 1. Empty array marks the default audience — the fallback for users who match no other segment |
paywall_id | string | Paywall ID (UUID) shown to users in this audience. Required when content_type is "paywall" |
flow_id | string | Flow ID (UUID) shown to users in this audience. Required when content_type is "flow" |
priority | number | 0-based, unique within the placement. Audiences are evaluated low-to-high; the default audience must have the highest value |
A placement must have exactly one default audience.
A placement’s content type is fixed when you create it, so placements update can’t switch a paywall placement to a flow or the reverse. Serve the flow from a placement of its own — see Create a new placement for your flow.
The CLI checks every entry before sending the request. An entry with a missing or unknown content_type, or without the ID its content_type requires, exits with code 2 and nothing is sent.
A flow can be attached only after it has been published. A draft flow, or one whose first publication is still in progress, is rejected by the server; the CLI recognizes that rejection and exits with code 2, printing the flows publish command for that flow. To publish a flow, use flows publish or the Flow & Paywall Builder, then wait for its status to reach published.
Example with one targeted audience and one default:
adapty placements update <placement-id> --app <app-id> --title "Main" --developer-id "main" \
--audiences '[{"content_type":"paywall","segment_ids":["<vip-segment-id>"],"paywall_id":"<vip-paywall-id>","priority":0},{"content_type":"paywall","segment_ids":[],"paywall_id":"<default-paywall-id>","priority":1}]'
Example of a placement that serves a published flow to all users:
adapty placements create --app <app-id> --title "Onboarding" --developer-id "onboarding" \
--audiences '[{"content_type":"flow","segment_ids":[],"flow_id":"<flow-id>","priority":0}]'
To swap a paywall across multiple placements without losing segment-specific routing:
-
Find affected placements:
adapty paywalls placements --app <app-id> <old-paywall-id> -
For each, read the full
audiencesarray:adapty placements get --app <app-id> <placement-id> --json -
Replace the matching
paywall_idvalues client-side. -
Write the modified payload back:
adapty placements update --app <app-id> <placement-id> --title "<title>" --developer-id "<developer-id>" --audiences '<modified-payload>'
Segments
Segments are read-only via the CLI. Create and edit them in the Adapty dashboard. Use these commands to look up segment IDs when composing placement audiences.
adapty segments list
List all segments for an app.
adapty segments list --app <app-id>
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
Accepts pagination flags.
adapty segments get
Get details for a specific segment.
adapty segments get --app <app-id> <segment-id>
| Argument | Description |
|---|---|
segment-id | Segment ID (UUID) |
| Flag | Required | Description |
|---|---|---|
--app | Yes | App ID (UUID) |
The response contains id, title, and description. Filter rules are not exposed via this API.
Auth
| Command | Description |
|---|---|
adapty auth login | Authenticate via browser using device flow |
adapty auth logout | Clear stored credentials locally |
adapty auth whoami | Verify token with the server and show user info |
adapty auth status | Show local authentication state without a server call |
adapty auth revoke | Revoke token server-side and clear locally |
See Authentication for full details on each command.