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

# The App object

> What an app represents, every field it returns, and how expand and permissions change its shape.

An app is one connected instance of an [integration](https://docs.lumos.com/reference/v1/objects/integration.md) in your
organization. `github.com` is an integration. When your organization connects GitHub, the result is
an app. If you connect the same integration twice, for example to a production tenant and to a
sandbox, you have two apps, and `instance_id` tells them apart.

Almost everything else in v1 belongs to an app. Its
[entitlements](https://docs.lumos.com/reference/v1/objects/entitlement.md) are the units of access you can grant on it. Its
[accounts](https://docs.lumos.com/reference/v1/objects/account.md) are the user, role, and service accounts that exist on
it. The three [workflows](https://docs.lumos.com/reference/v1/objects/workflow.md) bound to it decide what Lumos does when
someone requests access to it.

```json The App object theme={null}
{
  "id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
  "label": "GitHub",
  "app_class_id": "github.com",
  "instance_id": "acme-engineering",
  "logo_url": "https://logos.lumos.com/github.png",
  "website_url": "https://github.com",
  "category": "Developers",
  "description": "Source control and code review.",
  "label_override": null,
  "logo_url_override": null,
  "website_url_override": null,
  "category_override": null,
  "description_override": "Source control and code review.",
  "status": "approved",
  "disconnected": false,
  "post_approval_message": "Sign in with SSO to finish setting up your account.",
  "approval_workflow": { "id": "2b3c4d5e-6f70-8901-bcde-f12345678901" },
  "default_provisioning_workflow": { "id": "3c4d5e6f-7081-9012-cdef-123456789012" },
  "default_deprovisioning_workflow": null,
  "appstore_settings": { "in_app_store": true },
  "sync_status": "success"
}
```

## Attributes

| Field | Type | Description |
| - | - | - |
| `id` | string | Unique identifier for the app. Always present. |
| `label` | string | Display name of the app. Read-only. See [Display fields](#display-fields). |
| `app_class_id` | string | Catalog identifier of the underlying integration, such as `github.com`. Custom apps return `custom`. |
| `instance_id` | string | Distinguishes apps connected to the same integration. |
| `logo_url` | string | URL of the app logo. Read-only. |
| `website_url` | string | URL of the app's official website. Read-only. |
| `category` | string | The category this app belongs to. Read-only. |
| `description` | string | A description of the app. Read-only. |
| `label_override` | string or null | The display name set in your organization, as written. `null` when the app uses its default name. Always present. |
| `logo_url_override` | string or null | The logo URL set in your organization. `null` when the app uses its default logo. Always present. |
| `website_url_override` | string or null | The website URL set in your organization. `null` when the app uses its default website. Always present. |
| `category_override` | string or null | The category set in your organization. `null` when the app uses its default category. Always present. |
| `description_override` | string or null | The description set in your organization. `null` when the app uses its default description. Always present. |
| `status` | string | Lifecycle status. One of `discovered`, `in-review`, `needs-review`, `approved`, `blocklisted`, `deprecated`. |
| `disconnected` | boolean | Whether the app's stored credentials have been removed. Always present. |
| `post_approval_message` | string | Post-approval message, shown to the requester once their access request is approved. |
| `approval_workflow` | object or null | The approval workflow bound to this app. See [Bound workflows](#bound-workflows). |
| `default_provisioning_workflow` | object or null | The workflow that grants access on this app by default. |
| `default_deprovisioning_workflow` | object or null | The workflow that removes access on this app by default. |
| `appstore_settings` | object | AppStore membership and request settings. Contains only `in_app_store` unless you expand it. |
| `admins` | array | Users and groups that administer this app. Only present with `expand=admins`. |
| `custom_attributes` | object | Custom attribute values, keyed by attribute label. Only present with `expand=custom_attributes`. |
| `sync_status` | string | State of the most recent sync: `syncing`, `success`, or `failed`. See [Syncs and their status](#syncs-and-their-status). |

## Absent and null fields

The response omits fields that have no value instead of returning them as `null`. An app with no
`description` has no `description` key at all, so read the object with `.get()` semantics rather
than expecting every field in the table above.

Three exceptions break that rule on purpose:

* The response includes the five `*_override` fields as `null` when they aren't set.
* The response includes the three workflow fields as `null` when no workflow is bound. It omits
  one only when you can't read it.
* The response omits `appstore_settings` entirely when you can't read it, instead of returning it
  empty.

The last two let you distinguish "this app has no approval workflow" from "you can't see this
app's approval workflow." Everywhere else, an absent field has no value, or you didn't name it in
`expand`.

An expanded `appstore_settings` keeps its own fields that have no value, as `null`. It matches what
[Get AppStore Settings](https://docs.lumos.com/api-reference/v1/apps/get-appstore-settings.md) returns.

## Display fields

`label`, `logo_url`, `website_url`, `category`, and `description` are what people see. Each one
shows its `*_override` field when your organization set one, and the app's default otherwise. They're
read-only, so a create or update body that sends one returns `400`. Write the `*_override`
fields instead, as [Update metadata or credentials](#update-metadata-or-credentials) describes.

The overrides change only your organization's copy of the app, not the shared Lumos catalog. Lumos
stores each one exactly as you send it, even when it matches the default, so a later change to the
default doesn't change what you read back.

## Bound workflows

Every app has three workflow fields: `approval_workflow`, `default_provisioning_workflow`, and
`default_deprovisioning_workflow`. Each holds a reference to the bound workflow, or `null` when none
is bound.

```json theme={null}
"approval_workflow": { "id": "2b3c4d5e-6f70-8901-bcde-f12345678901" }
```

Name a workflow field in `expand` to get the full workflow definition inline instead of the
reference.

Each workflow field has its own permission check. Of the built-in roles, Admin, Read Only Admin,
and AppStore Read Only Admin can read all three fields on every app, and App Admin can read them
on the apps they administer. A workflow field you can't read is absent, as
[Absent and null fields](#absent-and-null-fields) describes.

To read or change which workflow is bound, use that field's own workflow endpoints, listed under
[Endpoints](#endpoints), rather than sending the whole app object.

## Expanding fields with `expand`

Reads return the base object. Pass `expand` to include fields that reads omit by default:

```bash theme={null}
curl -s 'https://api.lumos.com/v1/apps/1a2b3c4d-5e6f-7890-abcd-ef1234567890?expand=admins,custom_attributes' \
  --header 'Authorization: Bearer lsk_your_token'
```

Six fields are expandable: `admins`, `approval_workflow`, `default_provisioning_workflow`,
`default_deprovisioning_workflow`, `custom_attributes`, and `appstore_settings`.

A field you can't read is omitted rather than failing the request, as
[Requesting fields with `expand`](https://docs.lumos.com/reference/v1/overview#requesting-fields-with-expand) describes.

### `admins`

`admins` is an array of user and group references. Expanding it on an app with no admins returns an
empty array, not a missing key.

```json theme={null}
"admins": [
  { "id": "4d5e6f70-8192-0123-def1-234567890123", "type": "user" },
  { "id": "5e6f7081-9203-1234-ef12-345678901234", "type": "group" }
]
```

[Get App Admins](https://docs.lumos.com/api-reference/v1/apps/get-app-admins.md) returns the same list on its own. To change
it, send the complete list to [Set App Admins](https://docs.lumos.com/api-reference/v1/apps/set-app-admins.md). Anyone you
omit stops being an admin, and an empty list removes every admin. A user or group outside your
organization returns `422` with `code` set to `user.not_found` or `group.not_found`.

An app needs at least one admin before you add it to the AppStore. Setting `in_app_store` to `true`
on an app with no admins returns `409` with `code` set to `app.admin_required`, so set the admins
first. Removing the last admin doesn't take a listed app out of the AppStore.

### `custom_attributes`

`custom_attributes` is an object keyed by attribute label. Each value carries its own `type`, one
of `text`, `user`, or `single-select`. An app with no custom attributes configured may omit the key even when you
expand it.

```json theme={null}
"custom_attributes": {
  "Cost Center": { "type": "text", "value": "R&D" }
}
```

### `appstore_settings`

`appstore_settings` contains only `in_app_store` unless you expand it. Expanded, it returns the full
settings object that [AppStore settings](#appstore-settings) describes.
[Get AppStore Settings](https://docs.lumos.com/api-reference/v1/apps/get-appstore-settings.md) returns the same fields on
their own. Use it when you need only the settings.

## AppStore settings

[Update AppStore Settings](https://docs.lumos.com/api-reference/v1/apps/update-appstore-settings.md) is a merge patch that
takes these fields. Every field is optional, and a field you omit keeps its value. `null` clears a
field, except for four that always hold a value: `in_app_store`, `catalog_visibility`,
`allow_permission_selection`, and `allow_multiple_permission_selection`. `null` on one of them
returns `400`. A value you send for a list field replaces the whole list.

| Field | What it does |
| - | - |
| `in_app_store` | `true` adds the app to the AppStore, and `false` removes it. Send `true` or `false`, not `null`. |
| `catalog_visibility` | `visible` lists the app in the catalog. `search-only` returns it only to a catalog `search`. `hidden` hides it from requesters while it stays in the AppStore. |
| `request_instructions` | Text shown on the request form. |
| `allowed_requester_group_uuids` | The groups whose members can request the app, as group `id`s from [List Groups](https://docs.lumos.com/api-reference/v1/groups/list-groups.md). `null` or an empty list lets everyone request it. |
| `time_based_access` | The durations requesters can choose. See [Time-based access](#time-based-access). |
| `allow_permission_selection` | Whether requesters choose which entitlement they get. See [Entitlement selection](#entitlement-selection). |
| `allow_multiple_permission_selection` | Whether requesters can choose more than one entitlement in one request. |
| `default_entitlement` | The entitlement pre-selected on the request form, as `{ "id": "…" }`. See [Entitlement selection](#entitlement-selection). |
| `custom_intake_fields` | Questions the requester answers on the request form. See [Custom intake fields](#custom-intake-fields). |
| `request_validation_webhook_uuid` | An inline webhook that checks each request. See [Request validation](#request-validation). |
| `redirect_url` | A URL to send people to when they request the app, instead of the request flow. Up to 2,048 characters. |

### Time-based access

`time_based_access` has two fields:

| Field | What it does |
| - | - |
| `options` | The labels of the durations to offer. `null` or an empty list removes the app's own list, so the app offers your organization's default options. |
| `default` | The label pre-selected on the request form. It must be one of the app's own `options`. `null` clears it. |

```json theme={null}
{
  "time_based_access": {
    "options": ["7 days", "30 days"],
    "default": "7 days"
  }
}
```

A label must match one of your organization's options exactly, or the call returns `422` with
`code` set to `time_based_access.unknown_option`. New
organizations start with options such as `7 days`, `30 days`, and `Unlimited`. Your organization's
default options are the subset of its options that an app offers when it has no list of its own.

Sending `options` pins that list on the app, so later changes to your organization's default
options no longer apply to it. Send `default` together with `options`. While the app uses your
organization's default options, a `default` sent alone returns `422` with `code` set to
`time_based_access.default_not_offered`. To return to your
organization's default options, send both as `null`.

When you read the settings, `options` is `null` while the app uses your organization's default
options. Otherwise each option carries a `label` and a `value_seconds`, which is `null` for a
duration with no end.

### Custom intake fields

Each item in `custom_intake_fields` describes one question:

| Field | Required | What it does |
| - | - | - |
| `reference_key` | Yes | The field's key, up to 50 characters. It must start with a lowercase letter. The other characters must be lowercase letters, digits, or underscores. You can't change it after you create the field. |
| `field_type` | Yes | `text` or `dropdown`. It can't change once the field exists. |
| `prompt` | Yes | The question, up to 500 characters. |
| `description` | No | Guidance shown with the question, up to 500 characters. |
| `is_required` | Yes | Whether the requester must answer. |
| `dropdown_options` | No | The choices for a `dropdown` field, at least one and at most 100. A `text` field takes none. |

```json theme={null}
{
  "custom_intake_fields": [
    {
      "reference_key": "business_justification",
      "field_type": "text",
      "prompt": "Why do you need access?",
      "is_required": true
    },
    {
      "reference_key": "environment",
      "field_type": "dropdown",
      "prompt": "Which environment?",
      "is_required": true,
      "dropdown_options": ["Staging", "Production"]
    }
  ]
}
```

Send the whole list each time, up to 50 fields. Lumos matches fields by `reference_key`, updates the
ones you send, and deletes the ones you omit. `null` or an empty list deletes them all. A list that
breaks these rules returns `400` with `code` set to `appstore_settings.custom_intake_fields_invalid`.
`errors` lists every problem by position, such as `custom_intake_fields[2].reference_key`. `409`
means another call used the same `reference_key` at the same time.

### Entitlement selection

`allow_permission_selection` decides whether requesters pick an entitlement:

* With `true`, they choose from the app's visible entitlements, and
  `allow_multiple_permission_selection` decides whether they can choose more than one.
* With `false`, they can't choose. A request gets the app's `default_entitlement`, or no entitlement
  when none is set.

`default_entitlement` must be one of this app's entitlements, and it must have AppStore settings.
Otherwise the call returns `422` with `code` set to `entitlement.wrong_app` or
`entitlement.not_requestable`. Entitlements from
[Create Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/create-entitlement.md) always have them.

### Request validation

For `request_validation_webhook_uuid`, use the `id` of an
[inline webhook](https://docs.lumos.com/reference/v1/objects/inline-webhook.md) whose `type` is `request-validation`, from
[List Inline Webhooks](https://docs.lumos.com/api-reference/v1/inline-webhooks/list-inline-webhooks.md). A webhook of
another type returns `422` with `code` set to `request_validation_webhook.wrong_type`.

The app's webhook checks requests that don't name an entitlement. For a request that names
entitlements, Lumos calls each entitlement's own webhook instead of the app's, so set a webhook on
each entitlement too, as [AppStore settings](https://docs.lumos.com/reference/v1/objects/entitlement.md#appstore-settings)
on the Entitlement object describes.

## Syncs and their status

`sync_status` reports the state of the app's most recent sync, not the health of the app's
credentials. It moves from `syncing` to `success` or `failed`. `sync_status` is absent when Lumos
has no sync result for the app, for example because the app has never synced or was disconnected.
An absent `sync_status` doesn't mean that a sync failed.

[Trigger App Sync](https://docs.lumos.com/api-reference/v1/apps/trigger-app-sync.md) starts a sync and returns `202` with an
operation instead of waiting for the sync to finish. `sync_type` is required, and `full-sync` is the
only value it accepts today. Any other value returns `400`.

```bash theme={null}
curl -s -X POST 'https://api.lumos.com/v1/apps/1a2b3c4d-5e6f-7890-abcd-ef1234567890:sync' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{ "sync_type": "full-sync" }'
```

```json Response theme={null}
{
  "operation": {
    "id": "YXBwX3N5bmM6MWEyYjNjNGQtNWU2Zi03ODkwLWFiY2QtZWYxMjM0NTY3ODkwOmZ1bGxfc3luYw==",
    "done": false,
    "result": null,
    "error": null,
    "metadata": {
      "type": "app_sync",
      "app_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
      "sync_type": "full-sync"
    }
  }
}
```

Poll [Get Operation](https://docs.lumos.com/api-reference/v1/operations/get-operation.md) with the operation's `id` until
`done` is `true`, as [Long-running operations](https://docs.lumos.com/reference/v1/long-running-operations.md) describes.
At that point the operation carries `result` if the sync succeeded, or `error` with `code` set to
`app_sync.failed` if it failed. The operation is a view of the app's latest sync rather than a
record of one run, and it reads the same state as `sync_status`.

Only one sync runs per app at a time. If you request a sync while another sync is running on the
app, Lumos returns `409` with `code` set to `app.sync_in_progress`. Lumos doesn't queue the second request.

### The first sync

A newly connected app's first sync waits for a review of its identity matching rules, which decide
the Lumos user that each of the app's accounts belongs to. Without custom rules, Lumos matches
accounts to users by email address. Until that sync starts, the app has no synced accounts or
entitlements, and [Trigger App Sync](https://docs.lumos.com/api-reference/v1/apps/trigger-app-sync.md) without
`skip_first_sync_review` returns `409`. Of the built-in roles, only Admin can start that sync, and a
custom role can also allow it. Start the first sync in one of two ways:

* In the Lumos UI, after reviewing the rules.
* With Trigger App Sync and `skip_first_sync_review: true`, which starts it without the review.

```bash theme={null}
curl -s -X POST 'https://api.lumos.com/v1/apps/1a2b3c4d-5e6f-7890-abcd-ef1234567890:sync' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{ "sync_type": "full-sync", "skip_first_sync_review": true }'
```

The flag has no effect once the app has completed a sync successfully. If the first sync fails,
the next one waits for review again, so send the flag again when you retry. If you send credentials
to an app that has never completed a sync, the sync that starts also waits for review.

## Creating, updating, disconnecting, and deleting apps

Each of these four operations has its own endpoint:

* **Create or connect.** [Create App](https://docs.lumos.com/api-reference/v1/apps/create-app.md) returns `201` with the new
  app.
* **Update or reconnect.** [Update App](https://docs.lumos.com/api-reference/v1/apps/update-app.md) returns `200` with the
  updated app. Sending credentials reconnects it.
* **Disconnect.** [Disconnect App](https://docs.lumos.com/api-reference/v1/apps/disconnect-app.md) removes the stored
  credentials and returns `200` with the app's `id`, its `app_class_id`, and `disconnected: true`.
  Reconnect it later by sending credentials to Update App.
* **Delete.** [Delete App](https://docs.lumos.com/api-reference/v1/apps/delete-app.md) removes the stored credentials in
  every case. For a custom app, it deletes the app together with its AppStore settings, admins, and
  custom attributes, and returns `204`. If the app still has accounts, or other Lumos data still
  references it, the call returns `409` with `code` set to `app.delete_blocked`, and the app stays
  in a disconnected state. An app connected through an integration is disconnected during the
  call, which returns `202` with an operation. Lumos then deletes its record in the background.

Disconnect and delete differ in what they promise. Disconnect also deletes the record once the app
has no accounts left and nothing else references it, which can happen after the call returns. It
returns `200` either way.

Delete tells you which happened. For a custom app, `204` means the app is gone, and `409` means
it's still readable in a disconnected state. `detail` says whether accounts or other data kept it.
After you remove its accounts, Delete can return `409` for a short time, until Lumos updates the
app's account count. For an app connected through an integration, poll the operation until `done`
is `true`, as [Long-running operations](https://docs.lumos.com/reference/v1/long-running-operations.md#app-delete) describes.

Disconnect, delete, and credential updates work only on apps connected through the API.
[List Apps](https://docs.lumos.com/api-reference/v1/apps/list-apps.md)
returns these apps for `connection_source=api`. Any other app returns `409`. An app created in the
Lumos UI stays managed in the UI, so automation can't overwrite its credentials. Metadata updates
work on any app.

### Create a custom app or connect an integration

[Create App](https://docs.lumos.com/api-reference/v1/apps/create-app.md) takes one of two bodies:

* **Connect an integration** with `app_class_id`, the credentials in `auth`, and any non-secret
  configuration in `settings`. The keys vary by integration, so read them from
  [Get Integration Connection Schema](https://docs.lumos.com/api-reference/v1/integrations/get-integration-connection-schema.md)
  rather than hardcoding them. Credentials that validate right away connect the app. Its first
  sync then waits for a review of the app's identity matching rules, or for you to start it
  without the review, as [The first sync](#the-first-sync) describes.
* **Create a custom app** with `label_override`, `category_override`, and `description_override`,
  and either no `app_class_id` or `app_class_id` set to `custom`. A custom app is an app that
  Lumos has no integration for, so you maintain its accounts yourself, for example with
  [Upload Accounts](https://docs.lumos.com/api-reference/v1/accounts/upload-accounts.md). It reports `app_class_id` as
  `custom`, so you can send back a body you read.

Either body can also set `logo_url_override`, `website_url_override`, `request_instructions`, and
`post_approval_message`, and connecting an integration can set the other overrides too. A body that
sends `auth`, `settings`, or `version` without an integration's `app_class_id` returns `400`.

For an integration that needs browser consent, send `auth: {}` and finish connecting it in the
Lumos UI. The API can't connect the integrations below at all, and returns `422` with `code` set to
`app.api_unsupported` for them:

* a CSV/flatfile app
* an integration whose `auth` or `settings` fields the API doesn't support yet

An on-prem integration that none of your connected on-prem agents run returns `409` with `code` set
to `app.on_prem_connector_unavailable`. Install the connector on an agent, then retry.

```bash Create a custom app theme={null}
curl -s -X POST 'https://api.lumos.com/v1/apps' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{
    "label_override": "Deploy Dashboard",
    "category_override": "Developers",
    "description_override": "Internal deploy dashboard."
  }'
```

### Update metadata or credentials

[Update App](https://docs.lumos.com/api-reference/v1/apps/update-app.md) treats two groups of fields differently:

* **Metadata** (`label_override`, `category_override`, `description_override`,
  `logo_url_override`, `website_url_override`, `request_instructions`, `post_approval_message`) is
  merge-patched. An omitted field keeps its value.
  * `null` clears an override, so the matching [display field](#display-fields) shows the app's
    default again. A custom app has no default name, description, or category, so `null` for one
    of those three returns `422` with `code` set to `app.field_not_clearable`.
  * An override can't be empty. `label_override` takes up to 255 characters,
    `description_override` up to 1,000, and the two URLs up to 2,048.
  * `request_instructions` ignores `null`, so this endpoint can't clear it.
  * `post_approval_message` takes up to 511 characters. It has no default, so `null` removes it,
    and an app with no message omits the field. `""` returns `400`.
* **Credentials** (`auth`, `settings`, `version`) are one group. Lumos replaces the group instead of
  merging it, so `auth` is required whenever you send `settings` or `version`. A body without
  `auth` returns `400`, and the stored credentials don't change.

  Sending any of the three reconnects the app with exactly what you sent. Lumos re-validates the
  credentials and starts a sync. If the app has never completed a sync, that sync waits for review,
  as [The first sync](#the-first-sync) describes. For an integration that needs browser consent,
  the reconnect waits for that consent in the Lumos UI.

If the app's sync started in the last few minutes, sending credentials returns `409` with `code`
set to `app.sync_in_progress`. The `Retry-After` header gives the wait in seconds.

### Reconciling apps connected through the API

`GET /v1/apps` takes a `disconnected` filter, because a disconnected app can stay readable. Pair
`disconnected=false` with `connection_source=api` to reconcile only the apps connected through the
API:

```bash theme={null}
curl -s 'https://api.lumos.com/v1/apps?connection_source=api&disconnected=false' \
  --header 'Authorization: Bearer lsk_your_token'
```

## AppStore catalog view

[Get AppStore Catalog](https://docs.lumos.com/api-reference/v1/apps/get-appstore-catalog.md) is the requester view of your
AppStore, and it deliberately returns less than the object above: no workflow fields, no
`post_approval_message`, no `admins`, no `custom_attributes`, and no `sync_status`. Its
`appstore_settings` is scoped to what a requester needs to see.

Don't write code that treats the two shapes as interchangeable. If you need the admin view of an
app, fetch it by ID.

## Endpoints

> [!NOTE]
>
> Every app ID in these paths is the `id` field of the object above.

| Endpoint | Path |
| - | - |
| [List Apps](https://docs.lumos.com/api-reference/v1/apps/list-apps.md) | `GET /v1/apps` |
| [Create App](https://docs.lumos.com/api-reference/v1/apps/create-app.md) | `POST /v1/apps` |
| [Get App](https://docs.lumos.com/api-reference/v1/apps/get-app.md) | `GET /v1/apps/{app_uuid}` |
| [Update App](https://docs.lumos.com/api-reference/v1/apps/update-app.md) | `PATCH /v1/apps/{app_uuid}` |
| [Disconnect App](https://docs.lumos.com/api-reference/v1/apps/disconnect-app.md) | `POST /v1/apps/{app_uuid}:disconnect` |
| [Delete App](https://docs.lumos.com/api-reference/v1/apps/delete-app.md) | `DELETE /v1/apps/{app_uuid}` |
| [Trigger App Sync](https://docs.lumos.com/api-reference/v1/apps/trigger-app-sync.md) | `POST /v1/apps/{app_uuid}:sync` |
| [List App Entitlements](https://docs.lumos.com/api-reference/v1/apps/list-app-entitlements.md) | `GET /v1/apps/{app_uuid}/entitlements` |
| [Get AppStore Catalog](https://docs.lumos.com/api-reference/v1/apps/get-appstore-catalog.md) | `GET /v1/apps/appstore-catalog` |
| [Get App Entitlement AppStore Catalog](https://docs.lumos.com/api-reference/v1/apps/get-app-entitlement-appstore-catalog.md) | `GET /v1/apps/{app_uuid}/entitlements/appstore-catalog` |
| [Get AppStore Settings](https://docs.lumos.com/api-reference/v1/apps/get-appstore-settings.md) | `GET /v1/apps/{app_uuid}/appstore-settings` |
| [Update AppStore Settings](https://docs.lumos.com/api-reference/v1/apps/update-appstore-settings.md) | `PATCH /v1/apps/{app_uuid}/appstore-settings` |
| [Get App Admins](https://docs.lumos.com/api-reference/v1/apps/get-app-admins.md) | `GET /v1/apps/{app_uuid}/admins` |
| [Set App Admins](https://docs.lumos.com/api-reference/v1/apps/set-app-admins.md) | `PUT /v1/apps/{app_uuid}/admins` |
| [Get App Approval Workflow](https://docs.lumos.com/api-reference/v1/apps/get-app-approval-workflow.md) | `GET /v1/apps/{app_uuid}/approval-workflow` |
| [Set App Approval Workflow](https://docs.lumos.com/api-reference/v1/apps/set-app-approval-workflow.md) | `PUT /v1/apps/{app_uuid}/approval-workflow` |
| [Get App Default Provisioning Workflow](https://docs.lumos.com/api-reference/v1/apps/get-app-default-provisioning-workflow.md) | `GET /v1/apps/{app_uuid}/default-provisioning-workflow` |
| [Set App Default Provisioning Workflow](https://docs.lumos.com/api-reference/v1/apps/set-app-default-provisioning-workflow.md) | `PUT /v1/apps/{app_uuid}/default-provisioning-workflow` |
| [Get App Default Deprovisioning Workflow](https://docs.lumos.com/api-reference/v1/apps/get-app-default-deprovisioning-workflow.md) | `GET /v1/apps/{app_uuid}/default-deprovisioning-workflow` |
| [Set App Default Deprovisioning Workflow](https://docs.lumos.com/api-reference/v1/apps/set-app-default-deprovisioning-workflow.md) | `PUT /v1/apps/{app_uuid}/default-deprovisioning-workflow` |
