# Get Available Apps

> GET /v1/apps/available · Apps platform API

Source: https://developer.kustomer.com/api/apps-platform/get-available-apps

```http
GET https://{orgname}.api.kustomerapp.com/v1/apps/available
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.apps.read`; or legacy `org.user.apps.read`, `org.admin.apps.read`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Fetches all apps available for installation.

## About Apps

An app is a packaged integration, described in one JSON app definition, that adds custom objects, views, workflows, hooks and settings to a Kustomer org. These endpoints list the app versions your org can install and the apps it has installed, along with the state of every component each install created.

Admins find apps in **Settings › Apps › App Directory**, where they install, configure and update them. Behind each listing is an app definition that a developer registered as a numbered version. Installing a version creates its components in the org: Klasses, KViews, hooks, triggers, actions, workflows and so on. The org keeps running that version until an admin installs a newer one. Registering and installing are covered in [Register and install](https://developer.kustomer.com/docs/apps/register-and-install); the endpoints on this page read the results.

#### Available apps and installed apps

The API has two views of an app:

| View | What it is |
| --- | --- |
| Available app | One registered version of a definition. `GET /v1/apps/available` lists every version your org may install, both your own private apps and public ones. |
| Installed app | The record of an app in your org: which `version` is installed, its overall `status` and `statusAt`, and what happened to each component. |

An available app carries the listing details (`title`, `description`, `iconUrl`, `visibility`) and the components as registered (`klasses`, `hooks`, `triggers`, `actions`, `workflows`, `cards`), plus `dependencies` on other apps. `system` is `true` for apps Kustomer provides itself, and you can filter on it with `system=true` or `false`. Use `fields` to return only the attributes you need, since full definitions can be large.

#### Component state

An installed app groups its components by type (`actions`, `cards`, `hooks`, `klasses`, `triggers`, `workflows`). Each one is keyed by component name and holds a `status` (such as `success`), a `statusAt` timestamp and the `id` of the object the install created in your org. Use that `id` to find, for example, the workflow an app installed, so you can open it with the workflows API.

#### App version IDs

Endpoints that take `{appVersion}` expect `<app>-<version>`, such as `kustomer-0.1.0`. On `GET /v1/apps/{appVersion}` you can also pass just `<app>` to get the version that is currently installed. Private apps are registered with your org ID appended to their name (`acme_orders` becomes `acme_orders_<orgId>`), so read the final name from the API rather than building it yourself.

#### Which endpoint to use

| To | Call |
| --- | --- |
| Browse the app versions your org can install | [`GET /v1/apps/available`](https://developer.kustomer.com/api/apps-platform/get-available-apps) |
| Read one registered version, including its full definition | [`GET /v1/apps/available/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-available-app) |
| List the apps installed in your org | [`GET /v1/apps`](https://developer.kustomer.com/api/apps-platform/get-installed-apps) |
| Check which version of an app is installed and how each component fared | [`GET /v1/apps/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-installed-apps-by-specific-version) |

These read endpoints accept the apps read roles, so agents' and admins' keys can both call them. Registering and installing apps needs a key with the `org.admin.apps` role. List endpoints are paginated with `page` and `pageSize`.

Related: [Apps platform](https://developer.kustomer.com/docs/apps), [Register and install](https://developer.kustomer.com/docs/apps/register-and-install), [KViews](https://developer.kustomer.com/api/apps-platform#kviews-klass-views), [Cards](https://developer.kustomer.com/api/apps-platform#cards)

### Recipes

#### 1. Check whether an org runs the latest version of your app

Compare the version of your app an org has installed with the newest one registered, for example before you ship a feature that needs the upgrade.

**Step 1.** [`GET /v1/apps/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-installed-apps-by-specific-version.md). Ask for the app by name alone to get the installed version. `current` is the version the org runs and `status` should be `installed`. A `404` means the app isn't installed. For a private app, use the full registered name, which includes your org ID.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/apps/$APP_NAME" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
INSTALLED=$(kusty api GET /v1/apps/$APP_NAME | jq -r '.data.attributes.current')
```

**Step 2.** [`GET /v1/apps/available`](https://developer.kustomer.com/api/apps-platform/get-available-apps.md). List the versions the org can install, with `fields` to keep the response small, and pick the highest `version` for your app.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/apps/available?fields=name,version&pageSize=100" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/apps/available --query fields=name,version --all \
  | jq -rs --arg app "$APP_NAME" 'map(.data.attributes | select(.name == $app) | .version)
      | sort_by(split(".") | map(tonumber)) | last'
```

> Admins upgrade in **Settings › Apps**. See [versioning](https://developer.kustomer.com/docs/apps/versioning) for how app versions work.

#### 2. Verify what an app install created

After installing or upgrading an app, confirm that every component it defines was set up, and find the objects it created in your org.

**Step 1.** [`GET /v1/apps/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-installed-apps-by-specific-version.md). Read the installed version. Components are grouped by type (`actions`, `cards`, `hooks`, `klasses`, `triggers`, `workflows`), each keyed by name with a `status`, `statusAt` and the `id` of what was created. List any whose `status` isn't `success`.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/apps/$APP_VERSION" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/apps/$APP_VERSION > app.json
jq -r '.data.attributes | to_entries[]
  | select(.key | IN("actions", "cards", "hooks", "klasses", "triggers", "workflows"))
  | .key as $type | .value | to_entries[]
  | select(.value.status != "success") | [$type, .key, .value.status] | @tsv' app.json
```

**Step 2.** [`GET /v1/workflows/{id}`](https://developer.kustomer.com/api/workflows/get-a-workflow-based-on-the-id.md). Use a component's `id` to open what it created. For a workflow, read it from the workflows API to see its trigger and steps.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/workflows/$WORKFLOW_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
WORKFLOW_ID=$(jq -r '.data.attributes.workflows | to_entries[0].value.id' app.json)
kusty api GET /v1/workflows/$WORKFLOW_ID
```

#### 3. Inventory the apps installed in an org

List every installed app with its version and state, for example for a support handover or an audit of integrations.

**Step 1.** [`GET /v1/apps`](https://developer.kustomer.com/api/apps-platform/get-installed-apps.md). Page through the installed apps. Each one has its `name`, the `current` version and the install `status` with `statusAt`.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/apps?pageSize=100" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/apps --all \
  | jq -r '.data.attributes | [.name, .current, .status, .statusAt] | @tsv'
```

> Apps whose `status` is `failed` or `timed-out` didn't finish installing. Read one with [`GET /v1/apps/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-installed-apps-by-specific-version) to see which components failed.

### Example object

A real record from [`GET /v1/apps/{appVersion}`](https://developer.kustomer.com/api/apps-platform/get-installed-apps-by-specific-version.md):

```json
{
  "type": "installed_app",
  "id": "kustomer-0.1.0",
  "attributes": {
    "name": "kustomer",
    "current": "0.1.0",
    "version": "0.1.0",
    "status": "installed",
    "statusAt": "2016-11-14T23:51:28.314Z",
    "actions": {
      "kustomer.conversation.find-body": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.144Z",
        "id": "582a4e000eaec41000c3ddf0"
      },
      "kustomer.conversation.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.148Z",
        "id": "582a4e000eaec41000c3ddf1"
      },
      "kustomer.customer.find": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.150Z",
        "id": "582a4e000eaec41000c3ddf2"
      },
      "kustomer.conversation.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.153Z",
        "id": "582a4e0057761e100036fef3"
      },
      "kustomer.company.find": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.156Z",
        "id": "582a4e0057761e100036fef2"
      },
      "kustomer.customer.find-by-external-id": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.189Z",
        "id": "582a4e0057761e100036fef4"
      },
      "kustomer.kobject.find": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.211Z",
        "id": "582a4e000eaec41000c3ddf4"
      },
      "kustomer.customer.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.215Z",
        "id": "582a4e000eaec41000c3ddf6"
      },
      "kustomer.customer.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.218Z",
        "id": "582a4e000eaec41000c3ddf5"
      },
      "kustomer.klass.find-by-klassname": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.220Z",
        "id": "582a4e000eaec41000c3ddf3"
      },
      "kustomer.conversation.find-by-id": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.235Z",
        "id": "582a4e0057761e100036fef6"
      },
      "kustomer.message.find-last": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.237Z",
        "id": "582a4e0057761e100036fef5"
      },
      "kustomer.event.publish": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.242Z",
        "id": "582a4e0057761e100036fef9"
      },
      "kustomer.customer.find-by-email": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.243Z",
        "id": "582a4e0057761e100036fef7"
      },
      "kustomer.klass.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.245Z",
        "id": "582a4e0057761e100036fef8"
      },
      "kustomer.kobject.delete": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.248Z",
        "id": "582a4e0057761e100036fefa"
      },
      "kustomer.kobject.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.250Z",
        "id": "582a4e0057761e100036fefb"
      },
      "kustomer.kobject.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.252Z",
        "id": "582a4e0057761e100036fefc"
      },
      "kustomer.message.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.256Z",
        "id": "582a4e0057761e100036fefd"
      },
      "kustomer.message.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.258Z",
        "id": "582a4e0057761e100036fefe"
      },
      "kustomer.customer.find-by-phone": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.260Z",
        "id": "582a4e000eaec41000c3ddf7"
      },
      "kustomer.kobject.create-with-customer": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.264Z",
        "id": "582a4e000eaec41000c3ddf8"
      },
      "kustomer.kobject.find-by-external-id": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.269Z",
        "id": "582a4e000eaec41000c3ddfa"
      },
      "kustomer.regex-match.generic": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.271Z",
        "id": "582a4e000eaec41000c3ddfb"
      },
      "kustomer.message.find-by-id": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.272Z",
        "id": "582a4e000eaec41000c3ddfc"
      },
      "kustomer.message.find-by-external": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.275Z",
        "id": "582a4e000eaec41000c3ddfd"
      },
      "kustomer.rest-api.generic": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.276Z",
        "id": "582a4e000eaec41000c3ddfe"
      }
    },
    "cards": {
      "kustomer.customer.sentiment": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.025Z",
        "id": "582a4e009d84cd100022edff"
      },
      "kustomer.conversation.sentiment": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.090Z",
        "id": "582a4e009d84cd100022ee00"
      }
    },
    "hooks": {},
    "klasses": {},
    "triggers": {
      "kustomer.conversation.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.260Z",
        "id": "582a4e0057761e100036feff"
      },
      "kustomer.customer.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.262Z",
        "id": "582a4e0057761e100036ff00"
      },
      "kustomer.message.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.265Z",
        "id": "582a4e0057761e100036ff01"
      },
      "kustomer.customer.create": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.266Z",
        "id": "582a4e000eaec41000c3ddf9"
      },
      "kustomer.conversation.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.278Z",
        "id": "582a4e000eaec41000c3ddff"
      },
      "kustomer.message.update": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.279Z",
        "id": "582a4e000eaec41000c3de00"
      }
    },
    "workflows": {
      "kustomer-assign-user-on-message-send": {
        "status": "success",
        "statusAt": "2016-11-14T23:51:28.312Z",
        "id": "582a4e0057761e100036ff05"
      }
    },
    "createdAt": "2016-11-14T23:51:27.897Z",
    "updatedAt": "2016-11-14T23:51:28.314Z",
    "modifiedAt": "2016-11-14T23:51:27.897Z"
  },
  "relationships": {
    "org": {
      "data": {
        "type": "org",
        "id": "582a4dffaa5f92110005ea1a"
      },
      "links": {
        "self": "/v1/orgs/582a4dffaa5f92110005ea1a"
      }
    },
    "modifiedBy": {
      "data": {
        "type": "user",
        "id": "582a4dffaa5f92110005ea1b"
      },
      "links": {
        "self": "/v1/users/582a4dffaa5f92110005ea1b"
      }
    }
  },
  "links": {
    "self": "/v1/apps/kustomer-0.1.0"
  }
}
```

Fields:

- `id` (string): `<app>-<version>`, such as `kustomer-0.1.0`. `GET /v1/apps/{appVersion}` takes this, or just `<app>` for the version currently installed.
- `attributes.name` (string): The app's name. Private apps are registered with your org ID appended, so read the name from the API rather than building it.
- `attributes.current` (string): The version of the app your org is running now. When it differs from `version`, this record describes another version, such as an older one.
- `attributes.version` (string): The version this record describes.
- `attributes.status` (string): The install state of this version: `installing`, `installed`, `failed`, `timed-out`, `uninstalled` or `not-installed`. An install that stays `installing` for too long is reported as `timed-out`.
- `attributes.statusAt` (string): When `status` last changed, for example when the install finished.
- `attributes.actions` (object): The workflow actions the install registered, keyed by action name. Each entry holds the component's `status`, `statusAt` and the `id` of what it created in your org.
- `attributes.cards` (object): The cards the install created, keyed by card name, with the same `status`, `statusAt` and `id`.
- `attributes.hooks` (object): The hooks the install created, keyed by name. Empty when the app defines none.
- `attributes.klasses` (object): The Klasses the install created, keyed by name. Each `id` is the Klass ID in your org.
- `attributes.triggers` (object): The workflow triggers the app registered, keyed by event name, such as `kustomer.conversation.create`.
- `attributes.workflows` (object): The workflows the install created, keyed by workflow name.
- `attributes.workflows.kustomer-assign-user-on-message-send.status` (string): `success` when this component was set up. After an install or upgrade, check every component's `status`, not just the app's.
- `attributes.workflows.kustomer-assign-user-on-message-send.id` (string): The ID of the workflow created in your org. Read it with `GET /v1/workflows/{id}`.

### Relationships

- Referenced by **Cards** via `relationships.app`: The app a card belongs to. On the installed app, the `cards` section records each card the install created and its status.

### Permissions

Fewest roles for a read-only integration: `org.permission.apps.read`. For every endpoint: `org.permission.apps.read`.

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `page` | integer | no | Page number to return. |
| `pageSize` | integer | no | Number of records to return per page. |
| `fields` | string | no | Comma-separated available app fields to include. |
| `system` | boolean | no | Filter available apps by system-app status. |

## Responses

### 200

OK

- `meta` (object, required)
  - `pageSize` (integer, required)
  - `page` (integer, required)
- `data` (array<object>, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `name` (string)
    - `version` (string)
    - `visibility` (string)
    - `dependencies` (array<string>)
    - `default` (boolean)
    - `system` (boolean)
    - `title` (string)
    - `iconUrl` (string)
    - `vendor` (string)
    - `description` (string)
    - `screenshots` (array<any>)
    - `website` (string)
    - `actions` (array<any>)
    - `cards` (array<any>)
    - `hooks` (array<any>)
    - `klasses` (array<any>)
    - `triggers` (array<object>)
    - `workflows` (array<object>)
    - `createdAt` (string)
    - `updatedAt` (string)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "meta": {
    "pageSize": 100,
    "page": 1
  },
  "data": [
    {
      "type": "available_app",
      "id": "chat-0.1.0",
      "attributes": {
        "name": "chat",
        "version": "0.1.0",
        "visibility": "public",
        "dependencies": [
          "kustomer-0.1.0"
        ],
        "default": true,
        "system": true,
        "title": "Chat",
        "iconUrl": "https://cdn.kustomerapp.com/chat/images/icon.png",
        "vendor": "Kustomer",
        "description": "Send & Receive Chat Messages",
        "screenshots": [],
        "website": "https://kustomer.com/",
        "actions": [],
        "cards": [],
        "hooks": [],
        "klasses": [],
        "triggers": [
          {
            "eventName": "kustomer.app.chat.message.receive",
            "outputTemplate": {
              "id": "/#data.id",
              "trackingId": "/#data.attributes.trackingId",
              "body": "/#data.attributes.body",
              "sentAt": "/#data.attributes.createdAt",
              "size": "/#data.attributes.body.length",
              "customer": "/#data.relationships.customer.data.id",
              "session": "/#data.relationships.session.data.id",
              "links": "/#data.links"
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "trackingId": {
                  "type": "string"
                },
                "body": {
                  "type": "string"
                },
                "sentAt": {
                  "type": "string"
                },
                "size": {
                  "type": "number"
                },
                "customer": {
                  "type": "string"
                },
                "conversation": {
                  "type": "string"
                },
                "links": {
                  "type": "object"
                }
              }
            }
          }
        ],
        "workflows": [
          {
            "name": "chat-message-receive",
            "description": "Create a message when a chat message is received.",
            "trigger": {
              "transitions": [
                {
                  "condition": {
                    "values": [
                      true
                    ],
                    "op": "true"
                  },
                  "target": "create-message"
                }
              ],
              "appVersion": "chat-0.1.0",
              "id": "chat-message",
              "eventName": "kustomer.app.chat.message.receive"
            },
            "steps": [
              {
                "params": {
                  "related": "/#steps.chat-message.links.self",
                  "size": "/#steps.chat-message.size",
                  "body": "/#steps.chat-message.body",
                  "sentAt": "/#steps.chat-message.sentAt",
                  "app": "chat",
                  "channel": "chat",
                  "id": "/#steps.chat-message.id",
                  "customer": "/#steps.chat-message.customer",
                  "conversation": "/#steps.chat-message.session",
                  "meta": {
                    "trackingId": "/#steps.chat-message.trackingId"
                  }
                },
                "appVersion": "kustomer-0.1.0",
                "action": "kustomer.message.create",
                "id": "create-message",
                "transitions": []
              }
            ]
          }
        ],
        "createdAt": "2016-11-14T22:32:44.079Z",
        "updatedAt": "2016-11-14T22:32:44.079Z"
      },
      "links": {
        "self": "/v1/apps/available/chat-0.1.0"
      }
    }
  ]
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

## Example request

```bash
curl --request GET \
  --url 'https://api.kustomerapp.com/v1/apps/available' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```
