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

# Migrate requestable permissions to entitlements

> How v0 requestable permissions map to v1 entitlements and their AppStore settings and bound workflows, and why stored requestable-permission IDs don't work in v1.

A v0 requestable permission was two things in one object: the grantable access itself, and its
AppStore settings in `request_config` (visibility, allowed groups, approvals, provisioning, and
webhooks).

v1 splits them. The [entitlement](https://docs.lumos.com/reference/v1/objects/entitlement.md) is the grantable access. What
v0 kept in `request_config` is now the entitlement's AppStore settings, at
`/v1/entitlements/{entitlement_uuid}/appstore-settings`, and its three bound workflows, so one v0
write often becomes several v1 calls.

## Identifiers

v0 requestable-permission IDs and v1 entitlement IDs are different values. Each v0 requestable
permission corresponds to exactly one v1 entitlement, but its v0 `id` won't work in a v1 path.
`GET /v1/entitlements/{entitlement_uuid}` returns `404` for it.

The same applies everywhere v1 refers to an entitlement. Access Policies list `entitlements` by
entitlement ID, access requests take `entitlement_ids`, and tasks carry an `entitlement_id`. No v1
response carries a requestable-permission ID.

## Endpoints

| v0 | v1 |
| - | - |
| `GET /appstore/requestable_permissions` | [List Entitlements](https://docs.lumos.com/api-reference/v1/entitlements/list-entitlements.md) |
| `GET /appstore/apps/{app_id}/requestable_permissions` | [List App Entitlements](https://docs.lumos.com/api-reference/v1/apps/list-app-entitlements.md) |
| `GET /appstore/requestable_permissions/{permission_id}` | [Get Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/get-entitlement.md) |
| `POST /appstore/requestable_permissions` | [Create Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/create-entitlement.md), then its AppStore settings and workflows |
| `PATCH /appstore/requestable_permissions/{permission_id}` | [Update Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/update-entitlement.md) for the label, description, and approval message, [Update Entitlement AppStore Settings](https://docs.lumos.com/api-reference/v1/entitlements/update-entitlement-appstore-settings.md), and the workflow endpoints |
| `DELETE /appstore/requestable_permissions/{permission_id}` | [Delete Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/delete-entitlement.md) |

The list filters changed too:

* `search_term` is now `search`, a case-insensitive substring match on `label`. There's no
  `exact_match`.
* `in_app_store` is now `visible_in_appstore`.
* `include_inherited_configs` is gone. Where the entitlement inherits a setting from its app, v1
  returns that override as `null`, not the app's value.
* List Entitlements has no `app_id` filter. Use List App Entitlements for one app.

The object changed shape. `app_class_id`, `app_instance_id`, `type`, and `request_config` are gone.
v1 adds `entitlement_type_label`, `source`, `description`, `description_override`, the three
workflow fields, `custom_approval_message_override`, and `appstore_settings`, which you get with
`expand=appstore_settings`. `source` tells you where the entitlement came from. `manual` means
someone created it in Lumos.

## Where each `request_config` field went

| v0 `request_config` field | v1 |
| - | - |
| `appstore_visibility`: `VISIBLE`, `HIDDEN` | `appstore_settings.visible_in_appstore`: `true`, `false` |
| `allowed_groups_override` and `allowed_groups` | `appstore_settings.allowed_requester_group_uuids_override`, which takes Lumos group IDs. `null` means the entitlement uses its app's allowed groups, and an empty list lets anyone request it |
| `request_approval_config`: approvers, manager approval, and stages | The entitlement's approval workflow override: [Get Entitlement Approval Workflow Override](https://docs.lumos.com/api-reference/v1/entitlements/get-entitlement-approval-workflow-override.md) and [Set Entitlement Approval Workflow Override](https://docs.lumos.com/api-reference/v1/entitlements/set-entitlement-approval-workflow-override.md). [Remove Entitlement Approval Workflow Override](https://docs.lumos.com/api-reference/v1/entitlements/remove-entitlement-approval-workflow-override.md) turns the override off |
| `request_approval_config.custom_approval_message` and its override flag | `custom_approval_message_override` on the entitlement, which holds the message when it overrides the app's and is `null` otherwise. Set it with [Update Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/update-entitlement.md). `null` makes the entitlement use the app's message |
| `request_fulfillment_config.time_based_access` and `time_based_access_override` | `appstore_settings.time_based_access_override`, which holds the options when the entitlement overrides the app's and is `null` otherwise |
| `request_fulfillment_config.provisioning_group` | An `add_to_group` step in the entitlement's provisioning workflow. See [Provisioning groups and webhooks](#provisioning-groups-and-webhooks) |
| `request_fulfillment_config.manual_steps_needed` and `manual_instructions` | A manual provisioning task (`manual_provisioning_task`) in the entitlement's provisioning workflow |
| `request_fulfillment_config.provisioning_webhook` | A `provisioning_webhook` step in the entitlement's provisioning workflow. See [Provisioning groups and webhooks](#provisioning-groups-and-webhooks) |
| `access_removal_inline_webhook` | A `deprovisioning_webhook` step in the entitlement's deprovisioning workflow. See [Provisioning groups and webhooks](#provisioning-groups-and-webhooks) |
| `request_validation_inline_webhook` | `appstore_settings.request_validation_webhook_uuid`. `null` means no webhook validates requests for the entitlement. Unlike the other overrides, it doesn't fall back to the app's webhook |

## Creating an entitlement

v0 created a requestable permission and its whole `request_config` in one call. v1 takes several:

1. Call [Create Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/create-entitlement.md) with `app_id`,
   `label`, and optionally `description_override` and `custom_approval_message_override`.
2. Call [Update Entitlement AppStore Settings](https://docs.lumos.com/api-reference/v1/entitlements/update-entitlement-appstore-settings.md)
   to set visibility, allowed groups, time-based access, and the validation webhook.
3. Call the workflow endpoints to set the approval, provisioning, and deprovisioning workflows.

> [!WARNING]
>
> v1 makes a new entitlement visible in the AppStore as soon as it exists, so code ported from v0
> makes new entitlements requestable immediately. v0 created a requestable permission hidden unless
> the body set `appstore_visibility` to `VISIBLE`. To keep one hidden, set
> `visible_in_appstore` to `false` with Update Entitlement AppStore Settings right after you create
> it.

An entitlement's AppStore settings exist only while its app is in the AppStore. Until then,
reading or updating them returns `404`, and nobody can request the entitlement. v0 returned
`request_config` either way. Use this order:

1. Add the app to the AppStore while its `catalog_visibility` is still `hidden`. A new app starts
   as `hidden`.
2. Set each entitlement's `visible_in_appstore`.
3. Make the app `visible`.

[Set up an app in the AppStore](https://docs.lumos.com/reference/v1/guides/app-store-setup.md) describes each step.

```bash v0 theme={null}
curl -s -X POST 'https://api.lumos.com/appstore/requestable_permissions' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{
    "app_id": "2b3c4d5e-6f70-8901-bcde-f12345678901",
    "label": "Billing Admin",
    "request_config": { "appstore_visibility": "HIDDEN" }
  }'
```

```bash v1 theme={null}
curl -s -X POST 'https://api.lumos.com/v1/entitlements' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{
    "app_id": "2b3c4d5e-6f70-8901-bcde-f12345678901",
    "label": "Billing Admin"
  }'

curl -s -X PATCH 'https://api.lumos.com/v1/entitlements/1a2b3c4d-5e6f-7890-abcd-ef1234567890/appstore-settings' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{ "visible_in_appstore": false }'
```

## Provisioning groups and webhooks

v1 expresses these three v0 settings as steps in the entitlement's workflows:

| v0 setting | v1 step | Workflow `type` | Step input |
| - | - | - | - |
| `provisioning_group` | `add_to_group` | `entitlement-provisioning` | `group_id`, the group to add the account to |
| `provisioning_webhook` | `provisioning_webhook` | `entitlement-provisioning` | `provisioning_webhook_id`, an inline webhook's ID |
| `access_removal_inline_webhook` | `deprovisioning_webhook` | `entitlement-deprovisioning` | `deprovisioning_webhook_id`, an inline webhook's ID |

Inline webhook IDs come from
[List Inline Webhooks](https://docs.lumos.com/api-reference/v1/inline-webhooks/list-inline-webhooks.md). Create the workflow
with [Create Workflow](https://docs.lumos.com/api-reference/v1/workflows/create-workflow.md). Then bind it to the entitlement
with
[Set Entitlement Provisioning Workflow](https://docs.lumos.com/api-reference/v1/entitlements/set-entitlement-provisioning-workflow.md)
or
[Set Entitlement Deprovisioning Workflow](https://docs.lumos.com/api-reference/v1/entitlements/set-entitlement-deprovisioning-workflow.md).

## What v1 doesn't do yet

These v0 writes have no v1 equivalent yet. Until v1 supports them, make these changes in the Lumos
UI.

* **Renaming a synced entitlement.**
  [Update Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/update-entitlement.md) changes the label only
  for entitlements created in Lumos (`source` is `manual`). For any other entitlement, a new label
  returns `400`. v0 renamed any requestable permission.
* **Configuring an entitlement while its app isn't in the AppStore.** Add the app first, as
  [Creating an entitlement](#creating-an-entitlement) describes.

## Terraform

In version 1.x of the Lumos Terraform provider, `lumos_requestable_permission` becomes
`lumos_entitlement` and `lumos_entitlement_appstore_settings`, and its approval and provisioning
overrides move into workflows. You import each one by its entitlement's ID, which isn't the
permission's ID.
[Migrating from 0.x to 1.x](https://registry.terraform.io/providers/teamlumos/lumos/latest/docs/guides/migrating-from-0x)
covers finding those IDs and maps each attribute.
