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 — plus the commands that migrate a RevenueCat project, with their arguments, flags, and accepted values. For Apple Ads campaigns, see Ads Manager commands.

Global flags

These flags are available on all commands.

FlagDescription
--jsonOutput as JSON instead of formatted text
--helpShow command help

All list commands also accept pagination flags:

FlagDefaultDescription
--page1Page number
--page-size20Items 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>
ArgumentDescription
app-idApp ID (UUID)

adapty apps create

Create a new app.

adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app
FlagRequiredDescription
--titleYesApp title
--platformYesPlatform: ios or android. Repeat for both: --platform ios --platform android
--apple-bundle-idRequired with --platform iosApple bundle ID
--google-bundle-idRequired with --platform androidGoogle bundle ID

adapty apps update

Update an existing app.

adapty apps update <app-id> --title "New Name"
ArgumentDescription
app-idApp ID (UUID)
FlagDescription
--titleNew app title
--apple-bundle-idNew Apple bundle ID
--google-bundle-idNew 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>
FlagRequiredDescription
--appYesApp 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>
ArgumentDescription
access-level-idAccess level ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)

adapty access-levels create

Create a new access level.

adapty access-levels create --app <app-id> --sdk-id "pro" --title "Pro"
FlagRequiredDescription
--appYesApp ID (UUID)
--sdk-idYesIdentifier used in app code to check access (for example, "pro" or "premium")
--titleYesDisplay 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"
ArgumentDescription
access-level-idAccess level ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesNew 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>
FlagRequiredDescription
--appYesApp ID (UUID)

Accepts pagination flags.

adapty products get

Get details for a specific product.

adapty products get --app <app-id> <product-id>
ArgumentDescription
product-idProduct ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)

adapty products create

Create a new product.

Important

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
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesProduct title
--access-level-idYesAccess level ID (UUID) this product unlocks
--periodYesSubscription period: weekly, monthly, two_months, trimonthly, semiannual, annual, lifetime
--ios-product-idAt least one store requiredProduct ID from App Store Connect
--android-product-idAt least one store requiredProduct ID from Google Play Console
--android-base-plan-idRequired with --android-product-id unless --period lifetimeBase plan ID from Google Play Console
--stripe-product-idAt least one store requiredProduct ID from Stripe
--stripe-price-idRequired with --stripe-product-idPrice ID from Stripe
--paddle-product-idAt least one store requiredProduct ID from Paddle
--paddle-price-idRequired with --paddle-product-idPrice 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>
ArgumentDescription
product-idProduct ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--titleNoProduct title
--access-level-idNoAccess level ID (UUID) this product unlocks

Paywalls

adapty paywalls list

List all paywalls for an app.

adapty paywalls list --app <app-id>
FlagRequiredDescription
--appYesApp ID (UUID)

Accepts pagination flags.

adapty paywalls get

Get details for a specific paywall.

adapty paywalls get --app <app-id> <paywall-id>
ArgumentDescription
paywall-idPaywall ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)

adapty paywalls create

Create a new paywall.

adapty paywalls create --app <app-id> --title "Default Paywall" --product-id <product-id>
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesPaywall title
--product-idYesProduct ID (UUID). Repeat for multiple products: --product-id <id1> --product-id <id2>

adapty paywalls update

Replace all fields of an existing paywall.

Important

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.

ArgumentDescription
paywall-idPaywall ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesPaywall title
--product-idYesProduct 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>
ArgumentDescription
paywall-idPaywall ID (UUID)
FlagRequiredDescription
--appYesApp 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>
FlagRequiredDescription
--appYesApp ID (UUID)

Accepts pagination flags.

adapty flows get

Get details for a specific flow.

adapty flows get --app <app-id> <flow-id>
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)

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

StatusMeaning
draftThe flow has never been published
publishedThe current version is live
dirtyThe flow was published before, and the current version has unpublished changes. Users keep seeing the last published version
publishingPublication is in progress
publication_failedThe last publication failed. Fix the config and publish again
archivedThe 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"
FlagRequiredDescription
--appYesApp ID (UUID)
--nameYesFlow name

adapty flows update

Rename a flow.

adapty flows update --app <app-id> <flow-id> --name "Onboarding v2"
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--nameYesNew flow name

adapty flows publish

Publish the current version of a flow to your users.

adapty flows publish --app <app-id> <flow-id>
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--yes, -yNoPublish 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>
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp 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:

FieldDescription
publication_statusHow far publication of this flow version got: transforming, transformed, uploading, uploaded, published, or failed
transform_errorThe raw transform failure — either a JSON payload listing the issues or a summary string
publication_errorA 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
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--configOne of the twoBuilder config as a JSON string
--config-fileOne of the twoPath to a JSON file with the builder config, or - to read from stdin
--remote-configsNoJSON array of {locale, data} entries, where data is the remote config as a string
--expected-updated-atNoThe 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
ArgumentDescription
flow-idFlow ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--configOne of the twoBuilder config as a JSON string
--config-fileOne of the twoPath 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
ArgumentDescription
config-filePath to a local builder config JSON file
FlagDefaultDescription
--screenThe flow’s first screenScreen ID to render
--deviceiphone-14Device frame to render in
--orientationportraitportrait 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
ArgumentDescription
filePath to the image file
FlagRequiredDescription
--appYesApp 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>
FlagRequiredDescription
--appYesApp 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>
ArgumentDescription
placement-idPlacement ID (UUID)
FlagRequiredDescription
--appYesApp 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}]'
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesPlacement title
--developer-idYesString identifier used in app code to request this placement
--audiencesOne of the twoJSON array of audience entries, each with an explicit content_type. See Audiences shape
--paywall-idOne of the twoDeprecated. 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.

Warning

--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.

ArgumentDescription
placement-idPlacement ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)
--titleYesPlacement title
--developer-idYesString identifier used in app code to request this placement
--audiencesOne of the twoJSON array of audience entries, each with an explicit content_type. See Audiences shape
--paywall-idOne of the twoDeprecated. Paywall ID (UUID). Replaces all audiences with a single default audience
Warning

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:

FieldTypeDescription
content_typestring"paywall" or "flow". Required on every entry. All entries in one placement must have the same value
segment_idsstring[]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_idstringPaywall ID (UUID) shown to users in this audience. Required when content_type is "paywall"
flow_idstringFlow ID (UUID) shown to users in this audience. Required when content_type is "flow"
prioritynumber0-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:

  1. Find affected placements:

    adapty paywalls placements --app <app-id> <old-paywall-id>
  2. For each, read the full audiences array:

    adapty placements get --app <app-id> <placement-id> --json
  3. Replace the matching paywall_id values client-side.

  4. 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>
FlagRequiredDescription
--appYesApp ID (UUID)

Accepts pagination flags.

adapty segments get

Get details for a specific segment.

adapty segments get --app <app-id> <segment-id>
ArgumentDescription
segment-idSegment ID (UUID)
FlagRequiredDescription
--appYesApp ID (UUID)

The response contains id, title, and description. Filter rules are not exposed via this API.

Migrations

Move a RevenueCat project into Adapty: its catalog, then optionally its store events and transaction history. Adapty runs each migration as a sequence of steps and tells you which actions you can run next, so read status before each action. For the whole procedure, see Migration from RevenueCat.

All commands except list, create, use, current, and unuse accept the migration flag:

FlagRequiredDescription
-m, --migrationNoMigration ID. Without it, the CLI uses the ADAPTY_MIGRATION environment variable, then the migration saved by create or use.

adapty migrations list

List your migrations and the migration flows you can start, grouped by app.

adapty migrations list

adapty migrations create

Start a migration and save it as the current one.

adapty migrations create --name <app-name>
adapty migrations create --flow <flow> --app <app-id>
FlagRequiredDescription
--nameOne of --name or --flowName of the new Adapty app. Starts the catalog migration. Can’t be combined with --flow or --app.
--flowOne of --name or --flowFlow to start in an existing app, as adapty migrations list shows it. Requires --app.
--appWith --flowApp ID (UUID)
--no-selectNoCreate the migration without saving it as the current one

The flows available for an existing app after its catalog migration:

FlowDescription
transactionsImport the transaction history from a daily RevenueCat Cloud Export
transactions_supportImport the transaction history through RevenueCat support and Adapty support, for RevenueCat plans without Cloud Export
apple_eventsForward App Store notifications to Adapty while RevenueCat keeps receiving them
google_eventsSubscribe Adapty to the Pub/Sub topic RevenueCat uses for Google Play notifications

adapty migrations use

Save a migration as the current one, so the other commands don’t need -m.

adapty migrations use <migration-id>
ArgumentDescription
migration-idMigration ID from adapty migrations list

The CLI checks that you can access the migration before it saves the ID. The saved migration belongs to the current token and applies in every terminal.

adapty migrations current

Show the current migration and where it comes from: the ADAPTY_MIGRATION environment variable or the saved selection.

adapty migrations current

adapty migrations unuse

Clear the saved migration. An ADAPTY_MIGRATION value set in your shell stays in effect until you unset it.

adapty migrations unuse

adapty migrations status

Show the state of a migration, its issues, and the actions you can run next.

adapty migrations status
FlagRequiredDescription
--waitNoPoll until the migration changes, then return the latest state
--timeoutNoPolling time for --wait: 1–600 seconds, 120 by default. Accepts 300, 300s, or 5m. Requires --wait.

With --json, next_actions and available_actions list each action’s ID, the resources it reads, its input_schema, and its confirm text.

Exit code 0 means the request succeeded, not that the migration did. Check migration.state in the response.

adapty migrations steps

Show the migration checklist and the status of each step.

adapty migrations steps

adapty migrations show

List the resources you can read now, or read one.

adapty migrations show [resource]
ArgumentDescription
resourceResource name, for example apps, mapping, report, or export-config. Omit it to list the resources available at the current step.

adapty migrations run

Run an action from adapty migrations status.

adapty migrations run <action-id>
ArgumentDescription
action-idAction ID from next_actions or available_actions in adapty migrations status
FlagRequiredDescription
--inputNoAction input as a JSON object that matches the action’s input_schema. Without input, the CLI sends {}.
--input-fileNoPath to a file with the action input, or - to read it from stdin. Can’t be combined with --input.
-y, --yesFor actions with a confirm textConfirm the action after you read its confirm text. There is no interactive prompt.
--openNoOpen the action’s link even with a pipe or --json
--no-browserNoPrint the action’s link without opening a browser

Actions come in two kinds:

  • Input actions send your data to Adapty, for example the RevenueCat apps to migrate or your mapping decisions.
  • External actions open a page in the Adapty Dashboard, for example to paste the RevenueCat secret API key. Complete the page, then check status.

adapty migrations close

Finish or cancel a migration. You can’t reopen it afterwards.

adapty migrations close --outcome finish --yes
FlagRequiredDescription
--outcomeYesfinish marks the migration as completed; cancel abandons it
-y, --yesYesConfirm the closure

Auth

CommandDescription
adapty auth loginAuthenticate via browser using device flow
adapty auth logoutClear stored credentials and the saved migration locally
adapty auth whoamiVerify token with the server and show user info
adapty auth statusShow local authentication state without a server call
adapty auth revokeRevoke token server-side, then clear it and its saved migration locally

See Authentication for full details on each command.