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

---
id: 9340ff0f-b2ae-4168-ab71-579133c2aa37
---

# Feature flags

> Learn how to use the feature flags API to streamline migration from legacy CRM cards.

export const PostmanCard = ({title, collectionId}) => {
  return <div className="card-condensed-cta">
      <Card title={title ? title : "Postman collection"} href={`https://app.getpostman.com/run-collection/${collectionId}`} horizontal={true} cta="Run in Postman" icon={<svg xmlns="http://www.w3.org/2000/svg" width={25} height={25} preserveAspectRatio="xMidYMid" viewBox="0 0 256 256">
              <path fill="#FF6C37" d="M254.953 144.253c8.959-70.131-40.569-134.248-110.572-143.206C74.378-7.912 10.005 41.616 1.047 111.619c-8.959 70.003 40.569 134.248 110.572 143.334 70.131 8.959 134.248-40.569 143.334-110.7Z" />
              <path fill="#FFF" d="m174.2 82.184-54.007 54.007-15.229-15.23c53.11-53.11 58.358-48.503 69.236-38.777Z" />
              <path fill="#FF6C37" d="M120.193 137.47c-.384 0-.64-.128-.895-.384l-15.358-15.229a1.237 1.237 0 0 1 0-1.792c54.007-54.006 59.638-48.887 71.028-38.649.255.256.383.512.383.896s-.128.64-.383.896l-54.007 53.878c-.128.256-.512.384-.768.384Zm-13.437-16.509 13.437 13.438 52.087-52.087c-9.47-8.446-15.87-11.006-65.524 38.65Z" />
              <path fill="#FFF" d="m135.679 151.676-14.718-14.718 54.007-54.006c14.46 14.59-7.167 38.265-39.29 68.724Z" />
              <path fill="#FF6C37" d="M135.679 152.956c-.384 0-.64-.128-.896-.384l-14.718-14.718c-.256-.256-.256-.512-.256-.896s.128-.64.384-.895L174.2 82.056a1.237 1.237 0 0 1 1.791 0 15.58 15.58 0 0 1 4.991 11.902c-.256 14.206-16.38 32.25-44.28 58.614-.383.256-.767.384-1.023.384Zm-12.926-15.998c8.19 8.319 11.646 11.646 12.926 12.926 21.5-20.476 42.36-41.464 42.488-55.926.128-3.327-1.152-6.655-3.327-9.214l-52.087 52.214Z" />
              <path fill="#FFF" d="m105.22 121.345 10.878 10.878c.256.256.256.512 0 .768-.128.128-.128.128-.256.128l-22.524 4.863c-1.152.128-2.175-.64-2.431-1.791-.128-.64.128-1.28.512-1.664l13.053-13.054c.256-.256.64-.384.768-.128Z" />
              <path fill="#FF6C37" d="M92.934 139.262c-1.92 0-3.327-1.536-3.327-3.455 0-.896.384-1.792 1.024-2.432l13.053-13.054c.768-.64 1.792-.64 2.56 0l10.878 10.878c.768.64.768 1.792 0 2.56-.256.256-.512.384-.896.512l-22.524 4.863c-.256 0-.512.128-.768.128Zm11.902-16.51-12.542 12.543c-.256.256-.383.64-.128 1.024.128.383.512.511.896.383l21.116-4.607-9.342-9.342Z" />
              <path fill="#FFF" d="M202.739 52.238c-8.191-7.935-21.373-7.679-29.307.64-7.935 8.318-7.679 21.372.64 29.306A20.678 20.678 0 0 0 199.155 85l-14.59-14.59 18.174-18.172Z" />
              <path fill="#FF6C37" d="M188.405 89.223c-12.158 0-22.012-9.854-22.012-22.012 0-12.158 9.854-22.012 22.012-22.012 5.631 0 11.134 2.176 15.23 6.143.255.256.383.512.383.896s-.128.64-.384.895L186.357 70.41l13.566 13.566c.512.512.512 1.28 0 1.792l-.256.256c-3.327 2.047-7.295 3.199-11.262 3.199Zm0-41.337c-10.75 0-19.452 8.703-19.324 19.453 0 10.75 8.702 19.452 19.452 19.324 2.944 0 5.887-.64 8.575-2.047l-13.438-13.31c-.256-.256-.384-.512-.384-.896s.128-.64.384-.895l17.149-17.15c-3.456-2.943-7.807-4.479-12.414-4.479Z" />
              <path fill="#FFF" d="m203.122 52.622-.255-.256-18.301 18.044 14.461 14.462c1.408-.896 2.816-1.92 3.967-3.072a20.51 20.51 0 0 0 .128-29.178Z" />
              <path fill="#FF6C37" d="M199.155 86.28c-.384 0-.64-.128-.896-.384l-14.589-14.59c-.256-.256-.384-.512-.384-.896s.128-.64.384-.895l18.173-18.173a1.237 1.237 0 0 1 1.791 0l.384.256c8.575 8.574 8.575 22.396.128 31.098-1.28 1.28-2.687 2.432-4.223 3.328-.384.128-.64.256-.768.256Zm-12.798-15.87 12.926 12.926c1.024-.64 2.048-1.536 2.816-2.304 7.294-7.294 7.678-19.196.64-26.875L186.357 70.41Z" />
              <path fill="#FFF" d="M176.375 84.488a7.879 7.879 0 0 0-11.134 0l-48.247 48.247 8.063 8.063 51.062-44.792c3.328-2.816 3.584-7.807.768-11.134-.256-.128-.384-.256-.512-.384Z" />
              <path fill="#FF6C37" d="M124.929 142.077c-.384 0-.64-.128-.896-.383l-8.063-8.063a1.237 1.237 0 0 1 0-1.792l48.247-48.247a9.115 9.115 0 0 1 12.926 0 9.115 9.115 0 0 1 0 12.926l-.384.384-51.063 44.792c-.128.255-.384.383-.767.383Zm-6.143-9.342 6.27 6.271 50.167-44.024c2.816-2.304 3.072-6.527.768-9.342-2.303-2.816-6.526-3.072-9.342-.768-.128.128-.256.256-.512.384l-47.351 47.48Z" />
              <path fill="#FFF" d="M80.009 187.637c-.512.256-.768.768-.64 1.28l2.175 9.214c.512 1.28-.256 2.816-1.663 3.2-1.024.384-2.176 0-2.816-.768l-14.077-13.95 45.943-45.943 15.87.256 10.75 10.75c-2.56 2.175-18.045 17.149-55.542 35.961Z" />
              <path fill="#FF6C37" d="M78.985 202.61c-1.024 0-2.048-.383-2.688-1.151l-13.95-13.95c-.255-.256-.383-.512-.383-.896 0-.383.128-.64.384-.895l45.944-45.944c.256-.256.64-.384.895-.384l15.87.256c.383 0 .64.128.895.384l10.75 10.75c.256.256.384.64.384 1.024s-.128.64-.512.896l-.895.767c-13.566 11.902-31.995 23.804-54.902 35.194l2.175 9.086c.384 1.664-.384 3.456-1.92 4.352-.767.384-1.407.512-2.047.512Zm-14.078-15.997 13.182 13.054c.384.64 1.152.896 1.792.512.64-.384.896-1.152.512-1.792l-2.176-9.214c-.256-1.152.256-2.176 1.28-2.688 22.652-11.39 40.952-23.163 54.39-34.81l-9.47-9.47-14.718-.256-44.792 44.664Z" />
              <path fill="#FFF" d="m52.11 197.62 11.006-11.007 16.38 16.381-26.107-1.791c-1.151-.128-1.92-1.152-1.791-2.304 0-.512.128-1.024.512-1.28Z" />
              <path fill="#FF6C37" d="m79.497 204.146-26.236-1.791c-1.92-.128-3.199-1.792-3.071-3.712.128-.768.384-1.535 1.024-2.047L62.22 185.59a1.237 1.237 0 0 1 1.792 0l16.38 16.38c.385.385.512.897.257 1.408-.256.512-.64.768-1.152.768Zm-16.381-15.74-10.11 10.11c-.384.255-.384.895 0 1.151.127.128.255.256.511.256l22.652 1.536-13.053-13.054ZM104.452 146.557c-.768 0-1.28-.64-1.28-1.28 0-.384.128-.64.384-.896l12.414-12.414a1.237 1.237 0 0 1 1.792 0l8.062 8.063c.384.384.512.768.384 1.28-.128.384-.512.767-1.023.895l-20.477 4.352h-.256Zm12.414-11.902-8.446 8.446 13.821-2.943-5.375-5.503Z" />
              <path fill="#FFF" d="m124.8 140.926-14.077 3.071c-1.024.256-2.048-.384-2.303-1.408-.128-.64 0-1.28.511-1.791l7.807-7.807 8.063 7.935Z" />
              <path fill="#FF6C37" d="M110.467 145.277a3.168 3.168 0 0 1-3.2-3.2c0-.895.385-1.663.897-2.303l7.806-7.807a1.237 1.237 0 0 1 1.792 0l8.062 8.063c.384.384.512.768.384 1.28-.128.384-.512.767-1.023.895l-14.078 3.072h-.64Zm6.399-10.622-6.91 6.91c-.257.257-.257.512-.129.768s.384.384.768.384l11.774-2.56-5.503-5.502ZM203.25 64.907c-.256-.767-1.151-1.151-1.92-.895-.767.255-1.151 1.151-.895 1.92 0 .127.128.255.128.383.768 1.536.512 3.455-.512 4.863-.512.64-.384 1.536.128 2.048.64.512 1.536.384 2.048-.256 1.92-2.432 2.303-5.503 1.023-8.063Z" />
            </svg>} />
    </div>;
};

<PostmanCard collectionId="26126890-eec49579-b4ac-465c-b85a-7a2e1844807f" />

If you've built a [legacy public app](/apps/legacy-apps/public-apps/overview) that includes [legacy CRM cards](/api-reference/legacy/crm/extensions/crm-cards/guide), and you'd like to migrate your app to the latest version of the developer platform, you can leverage the feature flags API to provide a smooth migration experience for users who installed your app.

This functionality is mainly focused on legacy public apps that are already listed on the [HubSpot Marketplace](https://ecosystem.hubspot.com/marketplace/apps). If your app is not listed in the HubSpot Marketplace, you can begin creating new app cards after [migrating your app](/apps/developer-platform/build-apps/migrate-an-app/migrate-an-existing-public-app) without needing to set any feature flags on your account.

If you do want to selectively control which accounts can access your app's new cards, you can use the [feature flag API](#feature-flag-api-reference) to control each account's `flagState`.

## Migrate a public app to the developer projects framework

Using the CLI, you'll migrate an existing production public app to the projects framework. App features that are supported by projects, such as auth configuration and webhooks, will be included automatically in the migration.

### Prerequisites

This guide assumes that you meet the following criteria:

* You have an existing public app that has not yet been converted to the developer projects framework.
* You are ready to migrate your public app to the developer projects framework, enabling the creation of UI extensions for your app. If you want to start with a dry run of the migration, you can instead make a copy of your app in a project by running `hs project clone-app`.
* You have [set up your local environment for project development](/developer-tooling/local-development/hubspot-cli/install-the-cli) and set your developer account as the default in the CLI.
  * To view your connected accounts, run `hs accounts list` in the terminal. The terminal will list all currently connected accounts, along with the default.
  * If your developer account is connected but not the default, run `hs accounts use <accountNameOrID>`.

### Migrate legacy public app to the projects framework

To begin migration, you'll switch your public app to be configured using projects. This process will preserve the original auth credentials, and all other existing app features, HubSpot Marketplace listings, and app installs. No changes are required in your app backend, and customers will not experience any interruptions in service.

* Ensure you've installed the latest version (v7.6.0 or greater) of the HubSpot CLI by running the following command:

```shell theme={null}
npm i -g @hubspot/cli@latest
```

* With your developer account connected to the CLI and set as the default, run the command below:

```shell theme={null}
hs project migrate-app
```

* Select the **public app** that you'd like to migrate. This will create a new project containing a single public app component that represents the current state of your app.
* Enter a **name** and **local path** for your project, then press **Enter**. The terminal will then display a message to outline the migration process and confirm your intention to convert the app.
* Press **Enter** to confirm that you're ready to proceed with migration.
* The migration process will then begin, and the terminal will display the migration status. The migration includes:
  * Creating the project in your HubSpot account.
  * Converting the project-supported features of the app to source code files, which you can use int he future to update feature configuration.
  * Building and deploying the new project (Build #1), which completes the association between the public app and its project. This will preserve the original auth credentials, all app features, HubSpot Marketplace listing, and installs.
  * Downloading the new project source files to the specified local directory.

<Frame>
  <img src="https://www.hubspot.com/hubfs/Knowledge_Base_2023-24-25/developer-projects/migrate-legacy-public-app-in-preparation-for-feature-flag-usage-1.png" alt="Migrate a legacy public app to 2025.2 to use feature flags" />
</Frame>

With build #1 succeeded, you'll now have captured your original app's configuration state. As you continue to build your app and UI extensions, you can always safely revert to this state by redeploying build #1 by running the `hs project deploy --buildId=1` command.

Before you can begin UI extension development and run a local development server, deploy the successful build by running `hs project deploy`.

```shell theme={null}
hs project deploy
```

<Warning>
  After migration, features defined in the project source code will no longer be editable through HubSpot’s app management UI or developer APIs. You’ll instead need to manage those locally through the project using `hs project upload`. Other features, such as custom workflow actions or timeline events, can continue to be managed in the developer account app settings UI as before.
</Warning>

With the app successfully migrated, you can now update the public app with app cards. Learn more about creating app cards on the latest version of the developer platform [here](/apps/developer-platform/add-features/ui-extensions/extension-points/app-cards/overview).

## Workflow for HubSpot Marketplace apps

If your app is listed on the [HubSpot Marketplace](https://ecosystem.hubspot.com/marketplace/apps), your migrated app will automatically have a feature flag enabled that controls access to app cards in the accounts where the app is installed. You'll need to use the feature flag API to selectively enable accounts to use the new app cards. By default, app cards for listed public apps are restricted to a maximum of <u>five</u> accounts.

### Development workflow

<Steps>
  <Step title="Set test account feature flag">
    To start developing new app cards without impacting production accounts, first [create a test account](/getting-started/account-types#developer-test-accounts) within your developer account if you haven't done so yet. Then, using your developer account's developer API key, set your test account's feature flag to `ON` by making a `POST` request to the [feature flag API](/api-reference/legacy/app-management/feature-flags/flags/update-feature-flag).

    ```shell theme={null}
    curl -XPUT -s --json '{"flagState": "ON"}' 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/{portalId}?hapikey={developerApiKey}'
    ```

    With your test account feature flag configured, you'll be able to view new app cards in HubSpot as you develop your UI extensions.
  </Step>

  <Step title="Begin local development">
    * Start the local development server by running the following command:

    ```shell theme={null}
    hs project dev
    ```

    * Select your developer test account, then press **Enter**. The terminal will update with a message displaying the status of the development server. You can press **q** at any time to end the server.

    * When you're satisfied with your updates, upload your changes to your developer account.

    ```shell theme={null}
    hs project upload
    ```

    * When the build succeeds, deploy your changes by running the command below:

    ```shell theme={null}
    hs project deploy
    ```

    <Info>
      Alternatively, you can run both upload and deploy commands at the same time by running `hs project upload && hs project deploy`. You can also enable automatic deploy on successful build in the project's settings in your HubSpot account.
    </Info>
  </Step>

  <Step title="Continue testing and submit for review">
    You can continue testing your app and its new cards in additional accounts by using the feature flag API to set the `flagState` to `ON`, as shown in the first step above. You can enable this flag for up to five accounts, including beta customers.

    <Info>
      If at any point you want to start over, you can always safely revert the app by redeploying build #1 with the `hs project deploy --buildId=1` command.
    </Info>

    Once you've sufficiently tested your updated app, you'll need to submit it for review by emailing the following required information to [app-card-review@hubspot.com](mailto:app-card-review@hubspot.com):

    * Production app ID
    * Build ID
    * Hub ID of your developer account
    * Hub ID of the test account where the app is installed
    * Credentials or access to any third-party platform necessary to test the app card, if applicable
    * Demo video or detailed instructions of how users will interact with the card (such as a quick [Loom](https://www.loom.com/))
    * Additional context or details HubSpot might need that aren't covered by the above

    After submitting your app for review, invite `app-card-review@hubspot.com` as a user to your test account where the app is installed. Grant this user all the permissions necessary to fully test your app cards (for simplicity, Super Admin is recommended). A member of the review team will then test your app card and provide feedback if changes are needed. You'll continue to work with [app-card-review@hubspot.com](mailto:app-card-review@hubspot.com) to address provided feedback until all additional app card criteria are met.

    Once your app is approved, you can begin distributing it in the HubSpot Marketplace, and you will not need to resubmit it for approval when making future changes.
  </Step>

  <Step title="Distribute to the HubSpot Marketplace">
    After receiving approval for unlimited distribution from the App Card marketplace review process, your app will be ready for distribution. Before proceeding with app distribution, it's recommended to consider the following:

    * If your app previously included a legacy CRM card in the sidebar, consider [adding card update guidance](#add-card-update-guidance) so that users can seamlessly add your new cards and remove the old ones.
    * It’s recommended to [gradually roll out your app card updates](#gradually-roll-out-your-app-cards) to catch any issues before distributing to the full install base. You can also [roll out to all installed accounts](#roll-out-to-all-accounts-simultaneously) at the same time.
    * As your install base begins using your new app cards, you can [hide legacy CRM cards](#4.d-hiding-classic-crm-cards) from the onboarded accounts. The final step of migration is to delete the old cards from the app.
  </Step>
</Steps>

### Rollout strategies

#### Add card update guidance

To help users migrate to your new cards, HubSpot includes a default update state that you can apply to your classic cards. This update includes messaging to indicate that the card has available updates.

For account admins, a link to the app's settings page will be included. Non-admin users will see similar messaging, but will be guided to contact their account admin to assist with setup.

| Admin view                                                                                                                                                                                         | Non-admin view                                                                                                                                                                                             |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![super-admin-card-migration-view](https://knowledge.hubspot.com/hs-fs/hubfs/Knowledge_Base_2023_2024/old-crm-card-upgrade-banner.png?width=383\&height=539\&name=old-crm-card-upgrade-banner.png) | ![non-super-admin-card-migration-view](https://knowledge.hubspot.com/hs-fs/hubfs/Knowledge_Base_2023_2024/non-admin-card-upgrade-banner.png?width=371\&height=521\&name=non-admin-card-upgrade-banner.png) |

To add this state to your classic cards, include `"showMigrationMessage": "true"` in the card's JSON response. This should be included at the top-level of the response.

```json theme={null}
response.status(200).send({"showMigrationMessage": "true", "results": [crmCardDetails]});
```

Alternatively, you can build your own custom update state by manually updating the card's JSON response directly, or even using the feature flag API for conditional responses.

With the default update state enabled for your classic cards, their content will be replaced, and you can walk through what the end-user experience will be for super admins who want to upgrade to your new cards:

* In the test account, navigate to a CRM record that contains your classic card.

* On the CRM record, locate the card, then click the **Set up now** link to navigate to the app settings page.

  ![app-card-update-card](https://www.hubspot.com/hubfs/Knowledge_Base_2023_2024/set-up-card-now.png)

* The app settings page will display all available cards. Click the **link** provided for each card to navigate to the customization page for that object.

![app-settings-page](https://www.hubspot.com/hubfs/Knowledge_Base_2023_2024/app-settings-page.png)

* Users can then proceed to customize their record pages as needed. They can find your new cards within the *Apps* section of the customization sidebar.

![customize-ui-card-added](https://www.hubspot.com/hubfs/Knowledge_Base_2023_2024/customize-ui-card-added.png)

* After adding the new card, the old card can be removed by locating it in the view editor then clicking **Remove**. Alternatively, you can [hide the old card from the account](#4.d-hiding-classic-crm-cards) using the feature flag API.

  ![remove-card-from-sidebar](https://www.hubspot.com/hubfs/Knowledge_Base_2023_2024/remove-card-from-sidebar.png)

Learn more about the card updating user experience on [HubSpot's Knowledge Base](https://knowledge.hubspot.com/integrations/install-and-manage-app-cards).

#### Gradually roll out app cards

Using the feature flag API endpoints, you can gradually roll out your app in two ways:

* [Roll out app cards to new installs](#roll-out-to-new-installs)
* [Roll out app cards to a subset of accounts](#roll-out-to-a-subset-of-accounts)

##### Roll out to new installs

To roll out your app cards to new installs only, you'll use the feature flag API to turn off the `hs-release-app-cards` feature flag for all existing installs. Then, you'll switch the flag's state to `ON` so that new installs have the flag enabled by default.

<Warning>
  **Please note:** the `hs-release-app-cards` flag will apply for all app cards included in the app. You cannot selectively release individual cards within an app.
</Warning>

* For the first request, set the `flagState` to `OFF` for all accounts that currently have the app installed. You'll need to gather the `portalId` for all existing installed accounts, then make a `POST` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/batch/upsert?hapikey={developerAPIKey}`.

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
      "portalStates": [
        {
          "portalId": 1234,
          "flagState": "OFF"
        },
        {
          "portalId": 4567,
          "flagState": "OFF"
        },
        {
          "portalId": 78910,
          "flagState": "OFF"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
    curl --request POST \
      --url 'https://api.hubapi.com/feature-flags/v3/0/flags/hs-release-app-cards/portals/batch/upsert?hapikey={developerAPIKey}' \
      --header 'content-type: application/json' \
      --data '{
        "portalStates": [
          {
            "portalId": 1234,
            "flagState": "OFF"
          },
          {
            "portalId": 4567,
            "flagState": "OFF"
          },
          {
            "portalId": 78910,
            "flagState": "OFF"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

* With existing app installs set to `OFF`, you can now set the `defaultState` to `ON`. To do so, make a `PUT` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}`

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
      "defaultState": "ON"
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
    curl -- request PUT \
      --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}' \
      --header 'content-type: application/json' \
      --data '{
        "defaultState": "ON"
      }'
    ```
  </Tab>
</Tabs>

* Once you feel confident in new customer adoption, you can begin to remove customer `portalIds` that you switched to the `OFF` state by making a `POST` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/batch/delete?hapikey={developerAPIKey}` with the account IDs you want to remove from the `OFF` list.

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
      "portalIds": [1234, 4567, 78910]
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
    curl --request POST  \
      --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/batch/delete?hapikey={developerAPIKey}' \
      --header 'content-type: application/json; \
      --data '{
        "portalIds": [
          1234,
          4567,
          78910
        ]
      }'
    ```
  </Tab>
</Tabs>

<Info>
  To check which accounts still have their flag set to `OFF`, you can make a `GET` request to `/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/{portalId}`. Learn more in the [feature flag API reference documentation](/api-reference/legacy/app-management/feature-flags/portal-flag-states/get-accounts-with-flag-state).
</Info>

* When all previously added accounts have been deleted using the above endpoint, you'll have successfully completed the rollout and finished migration. At this point, you can safely delete your feature flag by making a `DELETE` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}`.

```shell theme={null}
curl --request DELETE \
  --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}'
```

#### Roll out to a subset of accounts

Alternatively, rather than starting with new installs, you can selectively enable your app cards for a subset of accounts that have your app installed. To do so, you'll need to have a list of the account IDs for all existing public app installs. With that list, you can make a `POST` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/batch/upsert?hapikey={developerAPIKey}` and set their `flagState` to `ON`.

<Tabs>
  <Tab tabId="0" title="JSON">
    ```json theme={null}
    {
      "portalStates": [
        {
          "portalId": 1234,
          "flagState": "ON"
        },
        {
          "portalId": 4567,
          "flagState": "ON"
        },
        {
          "portalId": 78910,
          "flagState": "ON"
        }
      ]
    }
    ```
  </Tab>

  <Tab tabId="1" title="cURL">
    ```shell theme={null}
    curl --request POST \
      --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards/portals/batch/upsert?hapikey={developerAPIKey}' \
      --header 'content-type: application/json' \
      --data '{
        "portalStates": [
          {
            "portalId": 1234,
            "flagState": "ON"
          },
          {
            "portalId": 4567,
            "flagState": "ON"
          },
          {
            "portalId": 78910,
            "flagState": "ON"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

You can continue making this request for subsets of accounts until all accounts have been migrated. Then, you can delete your feature flag by making a `DELETE` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}`.

```shell theme={null}
curl --request DELETE \
  --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}'
```

#### Roll out to all accounts simultaneously

To release your app cards to all installed accounts simultaneously, delete the app's feature flag by making a `DELETE` request to `https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}`.

```shell theme={null}
curl --request DELETE \
  --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-release-app-cards?hapikey={developerAPIKey}'
```

### Hiding legacy CRM cards

In addition to using the feature flags API to roll out app cards to your install base, you can also use it to facilitate the removal of legacy CRM cards by setting the `hs-hide-crm-cards` flag. For example, for existing installs, you may want to continue showing the old cards to remind users to upgrade to your new cards, but then hide them from new installs and accounts that have upgraded.

<Warning>
  **Please note:** the `hs-hide-crm-cards` flag will apply for all legacy CRM cards included in the app. You cannot selectively hide individual legacy CRM cards within an app.
</Warning>

To use the `hs-hide-crm-cards` flag to manage legacy CRM card access:

* Make a `PUT` request to set your app's `defaultState` to `OFF`. This initializes the app flag and ensures that the app's legacy CRM cards will be visible in every existing and new installed account.

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
        "defaultState": "OFF"
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
    curl --request PUT \
      --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-hide-crm-cards?hapikey={developerAPIKey}' \
      --header 'content-type: application/json' \
      --data '{
        "defaultState": "OFF"
      }'
    ```
  </Tab>
</Tabs>

* Next, set the `flagState` to `OFF` for all accounts that currently have the app installed. In the request body, you'll provide a `portalId` for each account.

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
      "portalStates": [
        {
          "portalId": 1234,
          "flagState": "OFF"
        },
        {
          "portalId": 4567,
          "flagState": "OFF"
        },
        {
          "portalId": 78910,
          "flagState": "OFF"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
        curl --request POST \
          --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-hide-crm-cards/portals/batch/upsert?hapikey={developerAPIKey}' \
          --header 'content-type: application/json' \
          --data '{
            "portalStates": [
              {
                "portalId": 1234,
                "flagState": "OFF"
              },
              {
                "portalId": 4567,
                "flagState": "OFF"
              },
              {
                "portalId": 78910,
                "flagState": "OFF"
              }
            ]
          }'
    ```
  </Tab>
</Tabs>

* With existing app installs set to `OFF`, make another request to set the `defaultState` to `ON`. This prevents new installs from ever seeing the app's legacy CRM cards.

```shell theme={null}
curl --request PUT \
  --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-hide-crm-cards?hapikey={developerAPIKey}'\
  --header 'content-type: application/json' \
  --data '{
    "defaultState": "ON"
  }'

```

* As you observe customers using the new app cards, such as receiving `hubspot.fetch()` calls from their accounts, you can remove them from the `hs-hide-crm-cards` flag list using the request below. Because you hid the legacy CRM cards from new installs, you'll only need to take this step for accounts you previously set to `OFF`.

<Tabs>
  <Tab title="JSON">
    ```json theme={null}
    {
      "portalIds": [1234, 4567, 78910]
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```shell theme={null}
    curl --request POST \
      --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-hide-crm-cards/portals/batch/delete?hapikey={developerAPIKey}'\
      --header 'content-type: application/json' \
      --data '{
        "portalIds": [
          1234,
          4567,
          78910
        ]
      }'
    ```
  </Tab>
</Tabs>

* When all previously added accounts have been removed from the flag list, you can be sure that your entire install base can no longer access the old legacy CRM cards. At this point, you can navigate to the app's settings page in your developer account and [delete the legacy CRM cards](/api-reference/legacy/crm/extensions/crm-cards/guide#delete-a-crm-card).

![delete-a-classic-crm-card-from-within-app-settings](https://www.hubspot.com/hubfs/Knowledge_Base_2023-24-25/public-app-delete-crm-card.png)

* Finally, make a request to delete the `hs-hide-crm-cards` flag from the app.

```shell theme={null}
curl --request DELETE \
  --url 'https://api.hubapi.com/feature-flags/v3/{appId}/flags/hs-hide-crm-cards?hapikey={developerAPIKey}'
```

## Feature flag API reference

Use the feature flag API to control availability of your app cards in customer accounts. All endpoints are under the `https://api.hubapi.com/feature-flags/v3/{appId}` root path. The API currently supports a single App Flag: `hs-release-app-cards`. Attempts to specify other App Flags will receive an error.

View the feature flag API reference endpoint documentation:

* **App flag endpoints:**
  * [Retrieve an app's feature flags](/api-reference/legacy/app-management/feature-flags/flags/get-feature-flag)
  * [Retrieve accounts with a set flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/get-accounts-with-flag-state)
  * [Set an app's feature flag](/api-reference/legacy/app-management/feature-flags/flags/update-feature-flag)
  * [Delete an app's feature flag](/api-reference/legacy/app-management/feature-flags/flags/delete-feature-flag)
* **Account flag state endpoints:**
  * [Delete an account flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/delete-portal-flag)
  * [Retrieve account flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/get-account-flag)
  * [Batch delete account flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/delete-portal-flag-batch)
  * [Batch set account flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/upsert-account-flag)
  * [Set an account flag state](/api-reference/legacy/app-management/feature-flags/portal-flag-states/update-account-flag)
