> ## 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 access requests and tasks

> Moving access-request and task calls from v0 to v1: new endpoints, entitlement IDs in place of requestable-permission IDs, renamed task filters, and the new value labels.

This guide covers the changes specific to access requests and tasks. For the conventions every
endpoint shares, see [What changes in v1](https://docs.lumos.com/reference/v1/migrate/what-changes.md).

## Access requests

| v0 | v1 |
| - | - |
| `GET /appstore/access_requests` | `GET /v1/access-requests` |
| `GET /appstore/access_requests/{id}` | `GET /v1/access-requests/{id}` |
| `POST /appstore/access_request` | `POST /v1/access-requests` |
| `DELETE /appstore/access_requests/{id}` | `POST /v1/access-requests/{id}:cancel` |

### Filing a request

[Create Access Request](https://docs.lumos.com/api-reference/v1/access-requests/create-access-request.md) keeps every body
field except `requestable_permission_ids`, which becomes `entitlement_ids`.

> [!WARNING]
>
> **Requestable-permission IDs stored from v0 don't work in `entitlement_ids`.** A v0 ID sent as an
> entitlement ID returns `404` with `code` set to `access_request.entitlement_not_found`. A body that
> still sends `requestable_permission_ids` returns `400`.
> [Migrate requestable permissions to entitlements](https://docs.lumos.com/reference/v1/migrate/permissions-to-entitlements.md)
> covers the ID change.

```bash v0 theme={null}
curl -s -X POST 'https://api.lumos.com/appstore/access_request' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{
    "app_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
    "requestable_permission_ids": ["6f708192-a3b4-4c5d-8e6f-708192a3b4c5"],
    "business_justification": "Maintaining the release pipeline this quarter."
  }'
```

```bash v1 theme={null}
curl -s -X POST 'https://api.lumos.com/v1/access-requests' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{
    "app_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
    "entitlement_ids": ["4d5e6f70-8192-4a3b-8c4d-5e6f70819203"],
    "business_justification": "Maintaining the release pipeline this quarter."
  }'
```

The call returns `201` with a response like this:

```json v1 response theme={null}
{
  "access_requests": [
    {
      "id": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
      "app_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
      "app_name": "GitHub",
      "requester_user": {
        "id": "7d8e9f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
        "email": "jane.doe@acme.com",
        "given_name": "Jane",
        "family_name": "Doe",
        "status": "active"
      },
      "target_user": {
        "id": "7d8e9f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
        "email": "jane.doe@acme.com",
        "given_name": "Jane",
        "family_name": "Doe",
        "status": "active"
      },
      "supporter_user": null,
      "status": "pending-approval",
      "notes": {},
      "expires_at": null,
      "expiration_in_seconds": null,
      "requested_at": "2026-09-01T17:02:10.905133Z",
      "entitlements": [
        { "id": "4d5e6f70-8192-4a3b-8c4d-5e6f70819203", "label": "Maintainer" }
      ]
    }
  ]
}
```

An `access_length` that the app doesn't offer returns `400`. v0 returned `422`.

### Reading requests

[List Access Requests](https://docs.lumos.com/api-reference/v1/access-requests/list-access-requests.md) and
[Get Access Request](https://docs.lumos.com/api-reference/v1/access-requests/get-access-request.md) have the same filters and
expansions across versions:
`user_id`, `requester_user_id`, `target_user_id`, `statuses`, and `expand`. The list uses page
tokens, like every v1 list. Beyond that, four things change:

* **Entitlements replace requestable permissions.** v0 listed what was requested under
  `requestable_permissions`, as full requestable-permission objects. v1 lists `entitlements`
  instead, as described in
  [Entitlements on a request](https://docs.lumos.com/reference/v1/objects/access-request.md#entitlements-on-a-request).
* **`sort` is now `order_by`.** Send `order_by=created_at` for oldest first, which is the default,
  or `order_by=created_at desc` for newest first. A `sort` parameter returns `400` with `code` set
  to `validation.unknown_query_parameter`.
* **`status` and `statuses` take labels.** See [Status values](#status-values).
* **Embedded tasks are v1 tasks.** With `expand=tasks`, each task has the shape and values that
  [Tasks](#tasks) describes.

Who can see a request hasn't changed, as
[Who can see a request](https://docs.lumos.com/reference/v1/objects/access-request.md#who-can-see-a-request) describes.

### Status values

`status` in responses and `statuses` in filters take lowercase kebab-case labels. `notes` is keyed
by the same labels. A v0 value in `statuses` returns `400`.

| v0 `status` | v1 `status` |
| - | - |
| `PENDING` | `pending` |
| `PENDING_MANAGER_APPROVAL` | `pending-manager-approval` |
| `MANAGER_APPROVED` | `manager-approved` |
| `MANAGER_DENIED` | `manager-denied` |
| `PENDING_APPROVAL` | `pending-approval` |
| `APPROVED` | `approved` |
| `DENIED` | `denied` |
| `EXPIRED` | `expired` |
| `CANCELLED` | `cancelled` |
| `PENDING_PROVISIONING` | `pending-provisioning` |
| `PENDING_MANUAL_PROVISIONING` | `pending-manual-provisioning` |
| `DENIED_PROVISIONING` | `denied-provisioning` |
| `PROVISIONED` | `provisioned` |
| `COMPLETED` | `completed` |
| `PENDING_DEPROVISIONING` | `pending-deprovisioning` |
| `PENDING_MANUAL_DEPROVISIONING` | `pending-manual-deprovisioning` |
| `TIME_BASED_EXPIRED` | `time-based-expired` |
| `TIME_BASED_EXPIRED_FAILED` | `time-based-expired-failed` |
| `TIME_BASED_EXPIRED_CANCELLED` | `time-based-expired-cancelled` |
| `REVERTING` | `reverting` |
| `REVERTED` | `reverted` |

The embedded users' `status` is a label too, such as `active`. For every user status, see
[The User object](https://docs.lumos.com/reference/v1/objects/user.md).

### Cancelling a request

v0 cancelled with `DELETE` and took the reason as a query parameter. v1 cancels with the `:cancel`
custom method and takes the reason in an optional JSON body:

```bash v1 theme={null}
curl -s -X POST 'https://api.lumos.com/v1/access-requests/9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d:cancel' \
  --header 'Authorization: Bearer lsk_your_token' \
  --header 'Content-Type: application/json' \
  --data '{"reason": "No longer needed."}'
```

* Both versions return `204`.
* Send the reason in the body. A `reason` query parameter returns `400` with `code` set to
  `validation.unknown_query_parameter`.
* If the request's status no longer allows cancelling, the call returns `409`. v0 returned `422`.
  [Cancelling](https://docs.lumos.com/reference/v1/objects/access-request.md#cancelling) lists the statuses you can cancel
  from.

## Tasks

| v0 | v1 |
| - | - |
| `GET /tasks` | `GET /v1/tasks` |
| `GET /tasks/{task_id}` | `GET /v1/tasks/{task_id}` |
| `GET /tasks/{task_id}/actions` | `GET /v1/tasks/{task_id}/actions` |
| `POST /tasks/{task_id}/complete` | `POST /v1/tasks/{task_id}:complete` |
| `POST /tasks/{task_id}/dismiss` | `POST /v1/tasks/{task_id}:dismiss` |
| `POST /tasks/{task_id}/perform-action` | `POST /v1/tasks/{task_id}:perform-action` |
| `POST /tasks/{task_id}/reassign` | `POST /v1/tasks/{task_id}:reassign` |
| `POST /tasks/{task_id}/comments` | `POST /v1/tasks/{task_id}/comments` |

### Listing tasks

Both versions of [List Tasks](https://docs.lumos.com/api-reference/v1/tasks/list-tasks.md) list only the tasks you can see,
as [Which tasks you can see](https://docs.lumos.com/reference/v1/objects/task.md#which-tasks-you-can-see) describes. Both
list only open tasks (`pending`, `accepted`, and `blocked`) unless you pass `status`. v1 renames or
replaces seven v0 parameters:

| v0 | v1 | Notes |
| - | - | - |
| `task_type` | `type` | Takes v1's type labels. See [Values](#values). |
| `task_category` | `category` | Takes v1's category labels. Ignored when `type` is set. |
| `assigned_identity_ids` | `assigned_user_ids` | The same user IDs. |
| `sort_by` and `sort_direction` | `order_by` | One parameter for field and direction. See the table below. |
| `page` and `size` | `page_token` and `page_size` | See [Pagination](https://docs.lumos.com/reference/v1/pagination.md). The maximum `page_size` is 100. |

`status`, `product_area`, `search`, `assigned_group_ids`, `access_request_id`, `show_all_tasks`,
and `expand` keep their names. `status` and `product_area` take v1's labels.

| v0 `sort_by` | v1 `order_by` |
| - | - |
| `createdAt` | `created_at` |
| `taskType` | `type` |
| `app` | `app` |
| `targetUser` | `target_user` |

To sort in descending order, add ` desc` after the field, as in `order_by=created_at desc`, which
is `order_by=created_at%20desc` in a URL. Without `order_by`, v1 lists newest first.

> [!NOTE]
>
> A v0 parameter name sent to v1, such as `task_type` or `sort_by`, returns `400` with `code` set
> to `validation.unknown_query_parameter`.

v1 checks parameter names and values. `status=PENDING` returns `400`, because v1
expects `pending`. [Filtering the list](https://docs.lumos.com/reference/v1/objects/task.md#filtering-the-list) lists the
other values that return an error.

To list your open approval tasks, 50 at a time:

```bash v0 theme={null}
curl -s 'https://api.lumos.com/tasks?task_category=APPROVAL&size=50' \
  --header 'Authorization: Bearer lsk_your_token'
```

```bash v1 theme={null}
curl -s 'https://api.lumos.com/v1/tasks?category=approval&page_size=50' \
  --header 'Authorization: Bearer lsk_your_token'
```

```json v1 response theme={null}
{
  "tasks": [
    {
      "id": "5c1d2e3f-4a5b-4c7d-8e9f-0a1b2c3d4e5f",
      "type": "access-request-approval",
      "category": "approval",
      "status": "pending",
      "description": "Review Jane Doe's request for access to GitHub.",
      "instructions": null,
      "product_area": "appstore",
      "app": { "id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890" },
      "target_user": {
        "id": "7d8e9f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
        "email": "jane.doe@acme.com",
        "given_name": "Jane",
        "family_name": "Doe",
        "status": "active"
      },
      "resolved_by": null,
      "created_at": "2026-09-01T17:02:11.482913Z",
      "updated_at": "2026-09-01T17:02:11.482913Z",
      "access_request_id": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
      "entitlement_id": null
    }
  ],
  "next_page_token": "PjF-YWNtZQ=="
}
```

### Task fields

| v0 | v1 |
| - | - |
| `task_type` | `type` |
| `task_category` | `category` |
| `requestable_permission_id` | `entitlement_id` |

* `entitlement_id` holds an entitlement ID, not the requestable-permission ID that
  `requestable_permission_id` held.
  [Entitlement IDs on tasks](https://docs.lumos.com/reference/v1/objects/task.md#entitlement-ids-on-tasks) covers when it's
  `null`.
* v0's task endpoints omitted fields that had no value. v1 returns them as `null`. The exceptions
  are `assignees`, `actions`, and `comments`, which appear only when you name them in `expand`.

### Values

`type`, `category`, `status`, and `product_area` take lowercase kebab-case labels in v1, in
responses and in filters alike. An unknown value in any of the four filters returns `400`.

Some v1 types cover more than one v0 type. Filtering by one of those labels returns tasks of every
v0 type behind it.

| v0 `task_type` | v1 `type` |
| - | - |
| `SUPPORT_REQUEST_APPROVAL_MANUAL_TASK`, `SUPPORT_REQUEST_APPROVAL_TASK` | `access-request-approval` |
| `MANAGER_APPROVAL_MANUAL_TASK`, `MANAGER_APPROVAL_TASK` | `manager-approval` |
| `ACCOUNT_CREATION_MANUAL_TASK` | `account-creation` |
| `MANUAL_PROVISIONING_MANUAL_TASK`, `SUPPORT_REQUEST_PROVISIONING_FLOWS_V2_MANUAL_TASK` | `manual-provisioning` |
| `FALLBACK_MANUAL_PROVISIONING_MANUAL_TASK` | `fallback-provisioning` |
| `ACCOUNT_REMOVAL_MANUAL_TASK` | `account-removal` |
| `ACCOUNT_DEPROVISIONING_MANUAL_TASK` | `account-deprovisioning` |
| `ACCOUNT_MODIFICATION_MANUAL_TASK` | `account-modification` |
| `MANUAL_DEPROVISIONING_MANUAL_TASK`, `SUPPORT_REQUEST_DEPROVISIONING_FLOWS_V2_MANUAL_TASK` | `manual-deprovisioning` |
| `OFFBOARDING_ACCOUNT_REMOVAL_MANUAL_TASK` | `offboarding-account-removal` |
| `REASSIGN_RESOURCE_OWNER_MANUAL_TASK` | `reassign-resource-owner` |
| `REMEDIATION_MANUAL_TASK` | `remediation` |
| `ERROR_MANUAL_TASK`, `SUPPORT_REQUEST_ERROR_MANUAL_TASK`, `SUPPORT_REQUEST_CREATION_ERROR_MANUAL_TASK` | `error` |
| `AGENT_ISSUE` | No v1 label. See below. |

| v0 `task_category` | v1 `category` |
| - | - |
| `APPROVAL` | `approval` |
| `MANAGER_APPROVAL` | `manager-approval` |
| `PROVISIONING` | `provisioning` |
| `DEPROVISIONING` | `deprovisioning` |
| `ERROR` | `error` |
| — | `ownership` |
| — | `remediation` |

| v0 `status` | v1 `status` |
| - | - |
| `PENDING` | `pending` |
| `ACCEPTED` | `accepted` |
| `BLOCKED` | `blocked` |
| `STAGED` | `staged` |
| `COMPLETED` | `completed` |
| `DISMISSED` | `dismissed` |
| `RETRIED` | `retried` |
| `EXPIRED` | `expired` |

The same status labels appear in `transition_to`, both in the actions a task lists and in the body
of [Perform Task Action](https://docs.lumos.com/api-reference/v1/tasks/perform-task-action.md).

| v0 `product_area` | v1 `product_area` |
| - | - |
| `ACCESS_REVIEWS` | `access-reviews` |
| `APPSTORE` | `appstore` |
| `ATTRIBUTE_SYNC` | `attribute-sync` |
| `MOVER` | `mover` |
| `OFFBOARDING` | `offboarding` |
| `ONBOARDING` | `onboarding` |
| `PLATFORM` | `platform` |
| `SAVINGS` | `savings` |

With `expand=assignees`, an assignee's `type` is `user` or `group`. v0 returned `USER` or `GROUP`.

### Acting on a task

Complete, dismiss, and reassign work as they did on v0, with the same bodies and the same status
code on success. v1 adds a `code` to several of their errors, which
[Acting on a task](https://docs.lumos.com/reference/v1/objects/task.md#acting-on-a-task) lists.

[Perform Task Action](https://docs.lumos.com/api-reference/v1/tasks/perform-task-action.md) accepts different values:

* **`action_type` takes a label**, such as `approve-access-request` rather than
  `APPROVE_SUPPORT_REQUEST`. The labels a task accepts are the `action_type` values in its actions,
  which [List Task Actions](https://docs.lumos.com/api-reference/v1/tasks/list-task-actions.md) returns, as does
  [List Tasks](https://docs.lumos.com/api-reference/v1/tasks/list-tasks.md) with `expand=actions`. A v0 action type returns
  `400` with `code` set to `task.action_unknown`.
* **`transition_to` takes a status label**, such as `completed` rather than `COMPLETED`. It must be
  one of the transitions the action lists. Otherwise the call returns `400` with `code` set to
  `task.transition_not_allowed`.

[Create Task Comment](https://docs.lumos.com/api-reference/v1/tasks/create-task-comment.md) returns `201` on both versions.
v0's response had no body. v1's response is the comment it created, with `body`, `created_by`, and
`created_at`.

### Task types v1 doesn't return

`AGENT_ISSUE` tasks have no v1 label. v0's task list already omitted them. v1 also omits them from
an access request's `tasks`, and reading or acting on one by ID returns `404`.
