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

# What changes in v1

> The changes every v1 endpoint shares: paths, custom methods, pagination, errors, status codes, IDs, and timestamps.

Most changes between v0 and v1 are the same on every endpoint. This page covers those shared
changes once. A resource that changed in its own ways has its own migration guide, and the
[endpoint map](https://docs.lumos.com/reference/v1/migrate/endpoint-map.md) says which endpoints need one.

## Paths

Every v1 path starts with `/v1`, and collection names are kebab-case:

| v0 | v1 |
| - | - |
| `/access_policies` | `/v1/access-policies` |
| `/activity_logs` | `/v1/activity-logs` |
| `/identity_events` | `/v1/identity-events` |
| `/inline_webhooks` | `/v1/inline-webhooks` |
| `/appstore/access_requests` | `/v1/access-requests` |

## Custom methods

An action that v0 exposed as a sub-path, or as a `DELETE`, is a `:verb` suffix on the resource in
v1:

| v0 | v1 |
| - | - |
| `POST /tasks/{task_id}/complete` | [`POST /v1/tasks/{task_id}:complete`](https://docs.lumos.com/api-reference/v1/tasks/complete-task) |
| `POST /tasks/{task_id}/dismiss` | [`POST /v1/tasks/{task_id}:dismiss`](https://docs.lumos.com/api-reference/v1/tasks/dismiss-task) |
| `POST /tasks/{task_id}/perform-action` | [`POST /v1/tasks/{task_id}:perform-action`](https://docs.lumos.com/api-reference/v1/tasks/perform-task-action) |
| `POST /tasks/{task_id}/reassign` | [`POST /v1/tasks/{task_id}:reassign`](https://docs.lumos.com/api-reference/v1/tasks/reassign-task) |
| `DELETE /appstore/access_requests/{id}` | [`POST /v1/access-requests/{id}:cancel`](https://docs.lumos.com/api-reference/v1/access-requests/cancel-access-request) |
| `DELETE /apps/{app_id}` | [`POST /v1/apps/{app_uuid}:disconnect`](https://docs.lumos.com/api-reference/v1/apps/disconnect-app) |
| `POST /apps/{app_id}/sync` | [`POST /v1/apps/{app_uuid}:sync`](https://docs.lumos.com/api-reference/v1/apps/trigger-app-sync) |
| `POST /accounts/upload` | [`POST /v1/accounts:upload`](https://docs.lumos.com/api-reference/v1/accounts/upload-accounts) |

> [!WARNING]
>
> [Delete App](https://docs.lumos.com/api-reference/v1/apps/delete-app.md) deletes the app. v0's
> `DELETE /apps/{app_id}` only disconnected it. To disconnect an app in v1, call
> [Disconnect App](https://docs.lumos.com/api-reference/v1/apps/disconnect-app.md).

Some HTTP clients and proxies percent-encode a colon in a path. Make sure yours send a literal `:`.

```bash theme={null}
curl -s -X POST 'https://api.lumos.com/v1/tasks/1a2b3c4d-5e6f-7890-abcd-ef1234567890:complete' \
  --header 'Authorization: Bearer lsk_your_token'
```

## Pagination

v0 paged three different ways. v1 pages one way, on every list:

| Endpoints | Request | Response |
| - | - | - |
| Most v0 lists | `page`, `size` | `items`, `total`, `page`, `size`, `pages` |
| v0 `GET /activity_logs` | `limit`, `offset` | `items`, `total`, `limit`, `offset`, `links` |
| v0 `GET /identity_events` | `cursor`, `limit` | `identity_events`, `next_cursor`, `total_count` |
| Every v1 list | `page_size`, `page_token` | A field named for the resource, such as `apps`, and `next_page_token` |

v1 returns no totals. [Pagination](https://docs.lumos.com/reference/v1/pagination.md) describes how to tell when you have
reached the last page.

## Errors

Every v1 error has the same body, with the error nested under `error`:

| | v0 | v1 |
| - | - | - |
| Error body | `{"detail": "..."}` | `{"error": {"detail", "type", "code", "errors"}}` |
| A request that fails validation | `422` | `400`, with `code` set to `validation_error` |
| A malformed UUID in a body | `401` | `400` |
| A query parameter the endpoint doesn't take | Ignored | `400`, with `code` set to `validation.unknown_query_parameter` |
| Rate limited | `429`, `{"error": "Too many requests"}` | `429`, the envelope with `code` set to `rate_limited` |

The `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers
are the same on both versions. v0 and v1 requests count toward one limit for your organization, as
[Rate limits](https://docs.lumos.com/reference/v1/authentication.md#rate-limits) describes.

Branch on `error.code` instead of on `detail` or the status alone, as
[Errors](https://docs.lumos.com/reference/v1/errors.md) describes.

## Not found and forbidden

v0 returned `403` for a user or group ID that it couldn't find. v1 returns `404`, as it does for
any ID it can't find, and keeps `403` for a call that you lack permission to make.

## Identifiers

v1 identifies most resources by a UUID in their `id` field, as
[Identifiers](https://docs.lumos.com/reference/v1/identifiers.md) describes. A
[requestable-permission ID that you stored from v0](https://docs.lumos.com/reference/v1/migrate/permissions-to-entitlements.md)
doesn't work on v1.

## Timestamps

v1 returns every timestamp in UTC, as ISO 8601 with a `Z` suffix, such as `2026-01-15T18:30:00Z`.
v0 timestamps carried no offset.

## Status codes

Every v1 endpoint that creates something returns `201`. Some of their v0 predecessors returned
`200`, including `POST /apps` and `POST /access_policies`.

An app sync, an account upload, an app review sync, and the delete of an app connected through an
integration finish in the background. The endpoints that start them
return `202` with an operation, which you poll with
[`GET /v1/operations/{operation_id}`](https://docs.lumos.com/api-reference/v1/operations/get-operation). Polling the
operation replaces v0's job endpoints. For each operation type, see
[Long-running operations](https://docs.lumos.com/reference/v1/long-running-operations.md).

## Enum values

v1 enum values are lowercase kebab-case labels, such as `pending`, `in-review`, or
`request-validation`. They're the same in responses, filters, path parameters, and request bodies.
v0 returned uppercase values, such as `APPROVED`. A v0 value sent to v1 returns `400`, and the
error lists the accepted labels.

A few fields don't use labels: activity log `event_type` and `outcome`, identity event
`changed_field`, the `state` in an account upload's result, error `type`, a subject filter's
`operator` and `datatype`, the `group` of each scope filter you send to
[Sync App Review](https://docs.lumos.com/api-reference/v1/access-reviews/sync-app-review.md), and a subject's removal
`error.code`.

Each migration guide maps the v0 values for its resource. [Users and roles](#users-and-roles) and
[User offboardings](#user-offboardings) map the values for resources that have no guide.

## Smaller changes

### Inline webhooks

[`GET /v1/inline-webhooks`](https://docs.lumos.com/api-reference/v1/inline-webhooks/list-inline-webhooks) returns a page, `{"inline_webhooks": [...], "next_page_token": ...}`.
v0 returned a bare array.

v1 renames the type field from `hook_type` to `type`, and changes its values:

| v0 `hook_type` | v1 `type` |
| - | - |
| `PRE_APPROVAL` | `pre-approval` |
| `PROVISION` | `provisioning` |
| `DEPROVISION` | `deprovisioning` |
| `REQUEST_VALIDATION` | `request-validation` |
| `SIEM` | `siem` |

[The Inline Webhook object](https://docs.lumos.com/reference/v1/objects/inline-webhook.md) covers the rest of the object.

### Users and roles

Wherever v1 returns a user, its `status` is `staged`, `active`, `suspended`, or `inactive`. v0
returned `STAGED`, `ACTIVE`, and so on. A user's custom attribute `type` is `text`, `user`, or
`single-select`, where v0 returned `TEXT`, `USER`, or `SINGLE_SELECT`.

v0 returned each role in `roles` and `role_added` as a name. v1 returns each one as a role object
with `id`, `label`, `is_custom`, and `resource_type`, as [Roles](https://docs.lumos.com/reference/v1/objects/user.md#roles)
describes.

v0's `role_name` path parameter on Add User Role and Remove User Role is `role_id` in v1, and it
takes the role's `id`. A built-in role's `id` is its v0 name in kebab case:

| v0 role name | v1 role `id` |
| - | - |
| `ORGANIZATION_ADMIN` | `organization-admin` |
| `READ_ONLY_ORGANIZATION_ADMIN` | `read-only-organization-admin` |
| `AUDITOR` | `auditor` |
| `APP_STORE_READ_ONLY_ADMIN` | `appstore-read-only-admin` |
| `APP_ADMIN` | `app-admin` |
| `VENDOR_OWNER` | `vendor-owner` |
| `VENDOR_AGREEMENT_OWNER` | `vendor-agreement-owner` |
| `MCP_GOVERNANCE` | `mcp-governance` |
| `USER` | `user` |

The path takes the `id` exactly as written. A v0 role name, such as `APP_ADMIN`, returns `400`
with `code` set to `role.id_required`. A custom role's `id` is a UUID, which List User Roles
returns. The path doesn't take a custom role's name.

### User offboardings

An offboarding's `status` is a label on
[Get User Offboarding](https://docs.lumos.com/api-reference/v1/lifecycle-management/get-user-offboarding.md) and every other
call that returns an offboarding:

| v0 `status` | v1 `status` |
| - | - |
| `SCHEDULED` | `scheduled` |
| `IN_PROGRESS` | `in-progress` |
| `DIVERTED` | `diverted` |
| `CANCELLED` | `cancelled` |
| `FAILED` | `failed` |
| `EXPIRED` | `expired` |
| `COMPLETED` | `completed` |

### `/info` and `/art`

`GET /info` and `GET /art` become [`GET /v1/info`](https://docs.lumos.com/api-reference/v1/meta/get-info) and
[`GET /v1/art`](https://docs.lumos.com/api-reference/v1/meta/get-art), with the same response bodies.
The v0 pair doesn't require a token. The v1 pair requires one, so `GET /v1/info` is a quick check
that both your token and your v1 access work.
