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

# Update App

> Update an app in place: its domain-specific metadata overrides, its integration credentials, or both.

The **metadata** fields are merge-patched: an omitted field keeps its current value. The `*_override` fields are stored exactly as sent and returned as written; send `null` to clear one, after which the response returns `null` for it and the matching read-only field (`label`, `description` and so on) shows the app's default. A custom app has no default name, description or category, so those three can't be cleared on one. `request_instructions` ignores `null` and keeps its current value; there is no way to clear it through this endpoint. The overrides apply to your organization's copy of the app, not to the shared Lumos app catalog. `post_approval_message` has no default, so `null` removes it.

The **credential** fields — `auth`, `settings` and `version` — are one group that is *replaced*, not merge-patched. Sending any of the three reconnects the integration with exactly what you send and discards any credentials you leave out, so `auth` is required whenever you send any of them; a partial credential body is rejected with 400 rather than silently erasing credentials. A custom app has no integration, so it refuses all three with 400. A body with none of the three never touches credentials.

On a reconnect the credentials are re-validated and a sync is triggered, so the app either reconnects in-band or waits on browser consent in the Lumos UI. For an app that has never completed a sync, that triggered sync is held for match-rule review the same way a first connect is; `POST /v1/apps/{app_uuid}:sync` with `skip_first_sync_review: true` releases it.



## OpenAPI

````yaml /api-reference/lumos-api-v1.json patch /v1/apps/{app_uuid}
openapi: 3.1.0
info:
  title: Lumos API (v1)
  description: >

    Lumos API v1 is the programmatic interface to your connected apps, the
    entitlements on them, and

    the workflows that grant access to those entitlements.


    Every path is prefixed with `/v1`. Authenticate with an API token, which
    inherits the permissions

    of the user who created it: a call returns what that user could see in the
    Lumos UI, and nothing

    more.


    New here? Browse what you can connect with `GET /v1/integrations`, read the
    credentials an

    integration expects with `GET
    /v1/integrations/{app_class_id}/connection-schema`, then connect it

    with `POST /v1/apps`.


    Every list endpoint shares one pagination contract. Set the page length with
    `page_size`, then send

    the `next_page_token` from a response back as `page_token` to fetch the next
    page. A `null`

    `next_page_token` means you have reached the end.


    Every error shares one envelope. Branch on the machine-readable `code`, not
    on `detail`.
  version: 0.1.0
servers:
  - url: https://api.lumos.com
security: []
tags:
  - name: Access Policies
    description: >

      An access policy grants apps, and optionally specific entitlements on
      them, to the identities that

      qualify under its `access_condition`, a Lumos Condition object.


      `POST /v1/access-policies` creates a policy and returns 201. `GET
      /v1/access-policies` lists

      policies, and `GET`, `PUT`, and `DELETE` on
      `/v1/access-policies/{access_policy_id}` read, replace,

      and delete one.


      Each entitlement a policy grants appears under `apps[].entitlements[]`,
      identified by its

      Entitlement UUID, the `id` that `GET /v1/entitlements/{entitlement_uuid}`
      returns.
  - name: Access Requests
    description: >

      An access request asks for access to an app, or to specific entitlements
      on it, for you or for

      another user.


      - `POST /v1/access-requests` creates requests, naming entitlements by
      Entitlement UUID in
        `entitlement_ids`, and returns them as a list.
      - `GET /v1/access-requests` and `GET /v1/access-requests/{id}` read
      requests.

      - `POST /v1/access-requests/{id}:cancel` cancels a pending request.


      Of the built-in roles, Admin, Read Only Admin, AppStore Read Only Admin,
      and App Admin can read

      every access request in your organization. Anyone else sees only the
      requests they made and the

      ones made for them.
  - name: Access Reviews
    description: >

      An access review is a campaign that reviews who has access to what across
      your connected apps.

      Each app in a campaign is an app review.


      v1 has two access-review endpoints so far, both scoped to one app review:


      - `GET
      /v1/access-reviews/{review_uuid}/apps/{app_review_uuid}/subject-filters`
      lists the fields
        you can filter the app review's subjects on. Each field comes with the operators it supports
        and, when it has a fixed set of values, the values it accepts.
      - `POST /v1/access-reviews/{review_uuid}/apps/{app_review_uuid}:sync` runs
      the app review's data
        import, optionally with new scope filters. It returns 202 with an operation. Poll
        `GET /v1/operations/{operation_id}` until `done` is true.

      You can't create, list, or update campaigns in v1 yet. Lumos enables these
      endpoints per

      organization, separately from the rest of v1, so contact your Lumos
      representative to turn them on.
  - name: Accounts
    description: >

      An account is a person's presence inside a connected app. Accounts arrive
      through sync; you cannot

      create one through this API.


      `GET /v1/accounts/{account_uuid}/entitlements` lists what one account
      holds. It reads the same

      relationship as `GET /v1/entitlements/{entitlement_uuid}/accounts`, from
      the account's side rather

      than the entitlement's.
  - name: Activity Logs
    description: >

      Activity logs record the actions taken across your organization's apps and
      identities.

      `GET /v1/activity-logs` lists them, newest first.


      Reading activity logs requires permission to view them across your
      organization. Of the built-in

      roles, Admin and Read Only Admin have it. Without it, the request returns
      403.
  - name: App Categories
    description: >

      App categories are the fixed set of categories an app can belong to, such
      as `Developers`.

      `GET /v1/app-categories` lists them as `{label}` objects.


      A `label` is the exact value to send as `category` to `POST /v1/apps` and

      `PATCH /v1/apps/{app_uuid}`. It is also the value the app read endpoints
      report. Read the list

      instead of hard-coding it.
  - name: Apps
    description: >

      An app is an integration you have connected, one per connected instance of
      a service. Your Okta

      tenant is an app. A second Slack workspace is a second app.


      ### Connecting one


      1. `GET /v1/integrations/{app_class_id}/connection-schema` to see which
      `auth` and `settings`
         keys the integration expects.
      2. `POST /v1/apps` with those credentials. Apps whose credentials validate
      right away connect, and
         their first sync waits for an admin to review match rules. It starts from the Lumos UI, or from
         `POST /v1/apps/{app_uuid}:sync` with `skip_first_sync_review: true`. Apps that need browser
         consent are finished in the Lumos UI.
      3. `GET /v1/apps/{app_uuid}` to follow the first sync. `sync_status` shows
      the state of the
         app's most recent sync. A sync started with `POST /v1/apps/{app_uuid}:sync` also returns an
         operation, which you poll with `GET /v1/operations/{operation_id}`.
      4. `POST /v1/apps/{app_uuid}:sync` to resync later. Only one sync runs per
      app at a time, so a
         second request while one is in flight returns 409.

      Rotate credentials with `PATCH /v1/apps/{app_uuid}`, which also updates an
      app's metadata.

      `POST /v1/apps/{app_uuid}:disconnect` drops the stored credentials and
      returns the app to a

      connectable state; `DELETE /v1/apps/{app_uuid}` removes the app outright.


      ### Reading apps


      `expand` is opt-in and evaluated per field: ask for `admins`,
      `custom_attributes`,

      `appstore_settings`, or any of the three workflow fields. A field you lack
      permission to read is

      left out of the response instead of failing the whole request, so a 200
      does not prove every field

      you asked for came back.


      To list only the connected apps you manage through the API, combine
      `connection_source=api` with

      `disconnected=false`.


      ### Bound workflows


      Each app carries three bindings: an approval workflow, a default
      provisioning workflow, and a

      default deprovisioning workflow. The two `default_` workflows are the ones
      that entitlements on

      the app fall back to. To bind a workflow to one entitlement instead, use
      the Entitlements

      endpoints.
  - name: Custom Attribute Definitions
    description: >

      Custom attributes are the extra fields your organization keeps on users.
      These endpoints read

      their *definitions*, not the values stored against any particular user.


      `GET /v1/custom-attribute-definitions` returns one entry per label,
      unified across every app that

      supplies it. Narrow the list with `source_type` to tell attributes synced
      from an app apart from

      ones your team created, or with `app_id` to see only what a single app
      supplies.


      `GET /v1/custom-attribute-definitions/{id}` reads one definition by its
      `id`, and

      `GET /v1/custom-attribute-definitions/{id}/configs` lists the configs
      behind it, highest priority

      first.
  - name: Entitlements
    description: >

      An entitlement is a grantable unit of access on an app: a role, a license
      tier, a group, or

      another access right. Accounts hold entitlements.


      - `POST /v1/entitlements` creates a requestable entitlement on an app.

      - `GET /v1/apps/{app_uuid}/entitlements` lists the entitlements on one
      app.

      - `GET /v1/entitlements/{entitlement_uuid}/accounts` lists who currently
      holds one.

      - `PATCH /v1/entitlements/{entitlement_uuid}` updates its `label`,
      `description`, and
        `custom_approval_message_override`. Sending any other field returns 400.
      - `DELETE /v1/entitlements/{entitlement_uuid}` refuses while the
      entitlement is still held,
        returning 409 with an `active_accounts` count.

      ### Per-entitlement workflows


      An entitlement can have its own approval override, provisioning workflow,
      and deprovisioning

      workflow, bound to it rather than to the whole app. Each has a GET and a
      PUT, and the approval

      override also has a DELETE that turns it off.


      An entitlement that can't be requested returns 404 with

      `Workflows are not available for this entitlement.` on each of these
      endpoints.
  - name: Groups
    description: >

      Lumos syncs groups from your connected apps, such as your Okta groups, and
      these endpoints read

      them.


      - `GET /v1/groups` lists groups. Filter by `name` (add `exact_match=true`
      to require an exact
        match), by `integration_specific_id` (the group's ID in the source system), or by `app_id`.
      - `GET /v1/groups/{group_id}` reads one group, and `GET
      /v1/groups/{group_id}/users` lists its
        members.

      An `app_id` that matches no app in your organization returns 404.
  - name: Identity Events
    description: >

      Identity events are the changes Lumos detects on your organization's
      identities, such as a change

      to a status, a group membership, or a custom attribute. `GET
      /v1/identity-events` lists them.

      Narrow the list with `identity_ids`, `changed_fields`, `start_time`, and
      `end_time`.


      A page can come back empty while `next_page_token` is still set, because
      events Lumos can't read

      are dropped after a page is fetched. Keep paging until `next_page_token`
      is absent, not until a

      page is empty.
  - name: Inline Webhooks
    description: >

      Inline webhooks are the webhooks your organization has configured in
      Lumos.

      `GET /v1/inline-webhooks` lists all of them, whatever their type.


      A webhook's `type` says where Lumos uses it.
  - name: Integrations
    description: >

      An integration is a service Lumos knows how to connect to, identified by
      an `app_class_id` such as

      `okta.com` or `workspace.google.com`. This is the catalog you connect
      *from*. Apps you have

      already connected are read through the Apps endpoints.


      Only connectable integrations appear here. Software discovered in your
      environment that has no

      Lumos integration behind it is excluded.


      ### Discovering how to connect


      1. `GET /v1/integrations?query=google` to find the integration. The filter
      matches both the
         `app_class_id` and the display name, so `google` returns `workspace.google.com` and
         `cloud.google.com`.
      2. `GET /v1/integrations/{app_class_id}/connection-schema` for the JSON
      schema of the `auth` and
         `settings` fields it expects.
      3. `POST /v1/apps` with those values.


      Step 2 is the point of this group: it lets you build a connect form
      without hardcoding one

      credential shape per integration.


      `GET /v1/integrations/{app_class_id}` and the connection schema return 404
      for any integration the

      list leaves out. The connection schema also returns 404 for an integration
      whose schema Lumos

      cannot describe yet.
  - name: Knowledge
    description: >

      Knowledge entries are the documents and notes Lumos agents draw on when
      they answer access

      questions. Each entry carries a title, body, tags, and product scopes,
      plus an optional file

      attachment.


      Because of that attachment, create and update send `multipart/form-data`
      rather than JSON. On

      update, tag and scope lists replace what was there instead of appending,
      and `clear_attachment=true`

      removes an existing file without uploading a replacement.


      `DELETE` deletes a knowledge entry. It no longer appears in list results,
      and you can't restore

      it through the API.


      Pages here are small: `page_size` defaults to 10 and is clamped to 25.
  - name: Lifecycle Management
    description: >

      Lifecycle management covers user offboardings. An offboarding runs your
      organization's

      offboarding workflow for one user, either right away or at a scheduled
      time.


      - `POST /v1/lifecycle-management/user-offboardings` starts an offboarding
      now, or at
        `scheduled_at` when you send a future time.
      - `GET /v1/lifecycle-management/user-offboardings/{user_offboarding_id}`
      reads one.

      - `POST
      /v1/lifecycle-management/user-offboardings/{user_offboarding_id}:cancel`
      cancels one that
        is scheduled or in progress.

      There is no list endpoint, so keep the `id` that create returns.


      `workflow_config_id` names an offboarding workflow configuration, not a
      workflow from

      `/v1/workflows`. Omit it to use the configuration your organization has
      selected for automatic

      offboarding. Only organizations with the multiple offboarding workflows
      feature can send it. For

      any other organization, a request that includes it returns 400.
  - name: Meta
    description: >

      `GET /v1/info` returns the API's current git revision, and `GET /v1/art`
      returns Lumos ASCII art.

      Use either to check your setup.


      Both require an API token. A 200 means your token works.
  - name: Operations
    description: >

      An operation tracks work that continues after the request that started it
      has returned. These

      endpoints start such work and respond with 202 and an operation:


      - `POST /v1/apps/{app_uuid}:sync`

      - `POST /v1/accounts:upload`

      - `POST /v1/access-reviews/{review_uuid}/apps/{app_review_uuid}:sync`


      Poll `GET /v1/operations/{operation_id}` until `done` is true. While
      `done` is false, neither

      `result` nor `error` is set. Once `done` is true, exactly one of them is.


      An app-sync operation shows the app's most recent sync, which can be a
      later run than the one you

      started.
  - name: Pre-Approval Rules
    description: >

      A pre-approval rule pre-approves matching access requests for an app.


      - `GET /v1/apps/{app_uuid}/pre-approval-rules` lists an app's rules, and
      `POST` on the same path
        creates one.
      - `GET`, `PATCH`, and `DELETE` on
      `/v1/apps/{app_uuid}/pre-approval-rules/{pre_approval_rule_id}`
        read, update, and delete one.

      If the app has been merged into another app, these endpoints work on the
      rules of the app it was

      merged into.


      Lumos enables condition-based pre-approval rules per organization,
      separately from the rest of v1,

      so contact your Lumos representative to turn them on.
  - name: Tasks
    description: >

      A task is work Lumos assigns to a person or group, such as approving an
      access request or

      provisioning access by hand. A workflow that creates a task waits for
      someone to act on it before

      it continues.


      ### Finding tasks


      `GET /v1/tasks` lists the tasks visible to you. `show_all_tasks=true`
      lists every task in your

      organization instead. It needs permission to view every task, which the
      built-in Admin, Read Only

      Admin, and AppStore Read Only Admin roles have, and which a custom role
      can also grant. Anyone

      else gets a 403.


      Filter with `type`, `category`, `status`, and `product_area`, whose values
      are lowercase and

      kebab-case. For example,

      `GET /v1/tasks?category=approval&product_area=appstore&status=pending`
      lists pending AppStore

      approvals.


      A task names the entitlement it grants or removes in `entitlement_id`, an
      Entitlement UUID.


      ### Acting on a task


      - `POST /v1/tasks/{task_id}:complete` approves an approval task, or
      completes another task with
        its one completion action.
      - `POST /v1/tasks/{task_id}:dismiss` denies an approval task, or dismisses
      another task without
        doing its work.
      - `POST /v1/tasks/{task_id}:perform-action` takes a specific action.
        `GET /v1/tasks/{task_id}/actions` lists the actions you can take and the statuses each one can
        move the task to, which are the values `transition_to` accepts.
      - `POST /v1/tasks/{task_id}:reassign` changes who the task is assigned to.
  - name: Users
    description: >

      Users are the people in your organization. These endpoints read them, and
      the only thing they

      change is a user's Lumos roles.


      - `GET /v1/users` lists users. `search` matches names and emails, and
      `exact_match=true`
        requires an exact match.
      - `GET /v1/users/current` returns the user who owns your API token.

      - `GET /v1/users/{user_id}` reads one user, and `GET
      /v1/users/{user_id}/accounts` lists the
        accounts that user holds.
      - `GET /v1/users/{user_id}/roles` lists a user's Lumos roles. Each role
      has an `id` (a built-in
        role's kebab-case name such as `app-admin`, or a custom role's UUID), a display `label`,
        `is_custom`, and a `resource_type` that is null for roles that apply across the organization.
        `POST /v1/users/{user_id}/roles/{role_id}` assigns one, and
        `DELETE /v1/users/{user_id}/roles/{role_id}` removes one, where `role_id` is the role's `id`.
        Assigning a role the user already has, or removing one they don't have, changes nothing.

      A user who has been deleted returns the same 404 as one who doesn't exist
      in your organization.
  - name: Workflows
    description: >

      A workflow is a reusable definition of the steps Lumos runs to approve a
      request, provision access,

      or deprovision it. Create the definition here, then bind it to an app or
      an entitlement through

      their own workflow endpoints.


      ### Building one


      1. `GET /v1/workflow-steps?app_id={app_uuid}&type={workflow type}` to
      discover the steps available
         for that app in the type of workflow you will create, each with the input schema it accepts.
         Without `type`, it lists only the steps every workflow type accepts.
      2. `POST /v1/workflows` with the steps you want.

      3. Bind it, for example with `PUT
      /v1/apps/{app_uuid}/default-provisioning-workflow`.


      `type` and `app_id` are fixed at creation. `PUT
      /v1/workflows/{workflow_id}` returns 400 for a

      change to either.


      ### Workflows this API cannot describe


      Some workflows Lumos builds for you, including the out-of-the-box
      provisioning defaults, contain

      steps with no public representation. `GET /v1/workflows` skips them, so a
      page can hold fewer items

      than `page_size` while more results remain. Treat an absent
      `next_page_token`, not a short page, as

      the end of the list. Binding one of these to an app or entitlement returns
      400.
paths:
  /v1/apps/{app_uuid}:
    patch:
      tags:
        - Apps
      summary: Update App
      description: >-
        Update an app in place: its domain-specific metadata overrides, its
        integration credentials, or both.


        The **metadata** fields are merge-patched: an omitted field keeps its
        current value. The `*_override` fields are stored exactly as sent and
        returned as written; send `null` to clear one, after which the response
        returns `null` for it and the matching read-only field (`label`,
        `description` and so on) shows the app's default. A custom app has no
        default name, description or category, so those three can't be cleared
        on one. `request_instructions` ignores `null` and keeps its current
        value; there is no way to clear it through this endpoint. The overrides
        apply to your organization's copy of the app, not to the shared Lumos
        app catalog. `post_approval_message` has no default, so `null` removes
        it.


        The **credential** fields — `auth`, `settings` and `version` — are one
        group that is *replaced*, not merge-patched. Sending any of the three
        reconnects the integration with exactly what you send and discards any
        credentials you leave out, so `auth` is required whenever you send any
        of them; a partial credential body is rejected with 400 rather than
        silently erasing credentials. A custom app has no integration, so it
        refuses all three with 400. A body with none of the three never touches
        credentials.


        On a reconnect the credentials are re-validated and a sync is triggered,
        so the app either reconnects in-band or waits on browser consent in the
        Lumos UI. For an app that has never completed a sync, that triggered
        sync is held for match-rule review the same way a first connect is;
        `POST /v1/apps/{app_uuid}:sync` with `skip_first_sync_review: true`
        releases it.
      operationId: v1UpdateApp
      parameters:
        - name: app_uuid
          in: path
          required: true
          schema:
            type: string
            description: The app's ID, which `GET /v1/apps` returns as `id`.
            title: App Uuid
          description: The app's ID, which `GET /v1/apps` returns as `id`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppUpdateInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppResponse'
        '400':
          description: >-
            Bad request — the request could not be processed. Common causes:
            missing or malformed credentials, an unknown `app_class_id`, or an
            invalid configuration value. See the `detail` field for the specific
            reason.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
          description: Unauthorized
        '403':
          description: >-
            Forbidden — the caller lacks permission to manage apps in your
            organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '404':
          description: Not found — no app with this UUID in your organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '409':
          description: >-
            Conflict — credentials were supplied for an app that is not managed
            via the API (`connection_source` is not `api`), so it cannot be
            reconnected here; or credentials were supplied while a sync is
            already in flight for this app (code `app.sync_in_progress`, with a
            `Retry-After` header in seconds).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '422':
          description: >-
            Unprocessable — credentials were supplied for an integration the API
            can't manage (code `app.api_unsupported`): a CSV/flatfile app, or
            one whose connection fields the API doesn't support yet. Manage it
            in the Lumos UI instead. Or `null` was sent for a custom app's
            `label_override`, `description_override` or `category_override`,
            which a custom app has no default for (code
            `app.field_not_clearable`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
          description: Too Many Requests
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
          description: Internal Server Error
        '501':
          description: Not implemented — this app does not support the requested operation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
        '502':
          description: >-
            Bad gateway — the third-party service failed, or launching the
            post-reconnect sync failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorEnvelope'
      security:
        - HTTPBearer: []
components:
  schemas:
    AppUpdateInput:
      properties:
        app_class_id:
          anyOf:
            - type: string
            - type: 'null'
          title: App Class Id
          description: >-
            Canonical identifier of an integration, e.g. `okta.com`. On create,
            an integration's id connects it with `auth`/`settings`. Omit it, or
            send `custom`, to create a custom app. On update it is optional and,
            when supplied, must match the app's own integration — a mismatch is
            rejected with 400.
        auth:
          anyOf:
            - type: object
            - type: 'null'
          title: Auth
          description: >-
            Credentials for the integration, as a JSON object — **all secrets go
            here**. The accepted keys depend on the integration; read them from
            `GET /v1/integrations/{app_class_id}/connection-schema` rather than
            hardcoding them. Some integrations connect in-band from these
            credentials; others require browser consent and are finished in the
            Lumos UI — for those, send `{}`. Missing or wrong-shaped credentials
            are rejected with 400, and so are credentials the third party
            rejects. Only applies to integrations. On update this field is
            required whenever `settings` or `version` is sent, because the
            credential group is replaced rather than merged.
        settings:
          anyOf:
            - type: object
            - type: 'null'
          title: Settings
          description: >-
            Non-secret configuration for the integration, as a JSON object —
            e.g. host, region, or tenant / instance URL. The accepted keys vary
            by integration and some integrations need none. Only applies to
            integrations.
        version:
          anyOf:
            - type: string
            - type: 'null'
          title: Version
          description: >-
            Optional integration version override. Pins the connection to a
            specific integration implementation/version instead of the current
            default; leave unset (`null`) unless directed otherwise. Only
            applies to integrations.
        label_override:
          anyOf:
            - type: string
              maxLength: 255
              minLength: 1
            - type: 'null'
          title: Label Override
          description: >-
            The app's display name in your organization, shown as `label`.
            Required when creating a custom app, and can't be cleared on one,
            since a custom app has no default name. On any other app, send
            `null` to clear it, so `label` shows the app's default name. It
            can't be empty. At most 255 characters.
        description_override:
          anyOf:
            - type: string
              maxLength: 1000
              minLength: 1
            - type: 'null'
          title: Description Override
          description: >-
            The app's description in your organization, shown as `description`.
            Required when creating a custom app, and can't be cleared on one,
            since a custom app has no default description. On any other app,
            send `null` to clear it, so `description` shows the app's default
            description. It can't be empty. At most 1,000 characters.
        category_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Category Override
          description: >-
            The app's category in your organization, shown as `category`.
            Required when creating a custom app, and can't be cleared on one,
            since a custom app has no default category. On any other app, send
            `null` to clear it, so `category` shows the app's default category.
            Possible values: 'Accounting & Finance', 'Marketing & Analytics',
            'Content & Social Media', 'Sales & Support', 'Design & Creativity',
            'IT & Security', 'Developers', 'HR & Learning', 'Office & Legal',
            'Communication', 'Collaboration', 'Commerce & Marketplaces',
            'Other', 'Internal'
        logo_url_override:
          anyOf:
            - type: string
              maxLength: 2048
              minLength: 1
            - type: 'null'
          title: Logo Url Override
          description: >-
            URL of the app's logo in your organization, shown as `logo_url`.
            Send `null` to clear it, so `logo_url` shows the app's default logo.
            It can't be empty. At most 2,048 characters.
        website_url_override:
          anyOf:
            - type: string
              maxLength: 2048
              minLength: 1
            - type: 'null'
          title: Website Url Override
          description: >-
            URL of the app's website in your organization, shown as
            `website_url`. Send `null` to clear it, so `website_url` shows the
            app's default website, if it has one. It can't be empty. At most
            2,048 characters.
        request_instructions:
          anyOf:
            - type: string
              maxLength: 511
            - type: 'null'
          title: Request Instructions
          description: >-
            Instructions shown to a requester when they request access to this
            app. Unlike the override fields, `null` is ignored here rather than
            clearing the current value.
        post_approval_message:
          anyOf:
            - type: string
              maxLength: 511
              minLength: 1
            - type: 'null'
          title: Post Approval Message
          description: >-
            Message sent to the requester when their access request is approved.
            `null` removes it.
      additionalProperties: false
      type: object
      title: AppUpdateInput
      description: >-
        Body of `PATCH /v1/apps/{app_uuid}`: update metadata overrides and/or
        rotate credentials.


        Metadata fields are merge-patched; `auth`, `settings` and `version` are
        replaced as one

        group. The router checks that group against the app, since only it knows
        whether the

        app is connected to an integration.
      examples:
        - description_override: Hand-rolled deploy dashboard.
          label_override: My internal tool
        - auth:
            api_key: 0123456789abcdef0123456789abcdef
          settings:
            app_instance_identifier: myorg.okta.com
    AppResponse:
      properties:
        id:
          type: string
          title: Id
          description: The unique identifier of the app.
        label:
          anyOf:
            - type: string
            - type: 'null'
          title: Label
          description: The display name of the app.
        app_class_id:
          anyOf:
            - type: string
            - type: 'null'
          title: App Class Id
          description: >-
            The catalog identifier of the underlying app (e.g. "github.com").
            Custom apps return "custom".
        instance_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Instance Id
          description: >-
            The app-instance identifier distinguishing multiple instances of the
            same app.
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
          description: URL of the app logo image.
        website_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Website Url
          description: URL of the app's official website.
        category:
          anyOf:
            - type: string
            - type: 'null'
          title: Category
          description: The category this app belongs to.
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: A description of the app.
        status:
          anyOf:
            - type: string
              enum:
                - discovered
                - in-review
                - needs-review
                - approved
                - blocklisted
                - deprecated
            - type: 'null'
          title: Status
          description: >-
            The lifecycle status of this app. One of `discovered`, `in-review`,
            `needs-review`, `approved`, `blocklisted`, `deprecated`.
        disconnected:
          type: boolean
          title: Disconnected
          description: >-
            Whether this app has been disconnected (its stored credentials
            removed via `POST /v1/apps/{app_uuid}:disconnect`). A disconnected
            app is excluded from `GET /v1/apps?disconnected=false`; reconnect it
            by sending credentials to `PATCH /v1/apps/{app_uuid}`.
          default: false
        label_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Label Override
          description: >-
            The display name set for this app in your organization, exactly as
            written. `label` shows it when set. Null when the app uses its
            default name. A custom app has no default name, so on one this is
            always the name it shows.
        description_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Description Override
          description: >-
            The description set for this app in your organization, exactly as
            written. `description` shows it when set. Null when the app uses its
            default description. A custom app has no default description, so on
            one this is always the description it shows.
        category_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Category Override
          description: >-
            The category set for this app in your organization, exactly as
            written. `category` shows it when set. Null when the app uses its
            default category. A custom app has no default category, so on one
            this is always the category it shows.
        logo_url_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url Override
          description: >-
            The logo URL set for this app in your organization, exactly as
            written. `logo_url` shows it when set. Null when the app uses its
            default logo.
        website_url_override:
          anyOf:
            - type: string
            - type: 'null'
          title: Website Url Override
          description: >-
            The website URL set for this app in your organization, exactly as
            written. `website_url` shows it when set. Null when the app uses its
            default website, if any.
        post_approval_message:
          anyOf:
            - type: string
            - type: 'null'
          title: Post Approval Message
          description: >-
            Custom message shown to the requester after their access request is
            approved. Omitted when none is set.
        admins:
          anyOf:
            - items:
                $ref: '#/components/schemas/AdminAssignee'
              type: array
            - type: 'null'
          title: Admins
          description: >-
            Users and groups that administer this app. Only present when
            expand=admins is requested.
        approval_workflow:
          anyOf:
            - $ref: '#/components/schemas/Workflow'
            - $ref: '#/components/schemas/WorkflowRef'
            - type: 'null'
          title: Approval Workflow
          description: >-
            The approval workflow for this app. Returns {id} by default; expand
            with expand=approval_workflow for the full workflow object. Omitted
            entirely if the caller lacks read access to approval workflow
            templates.
        default_provisioning_workflow:
          anyOf:
            - $ref: '#/components/schemas/Workflow'
            - $ref: '#/components/schemas/WorkflowRef'
            - type: 'null'
          title: Default Provisioning Workflow
          description: >-
            The default provisioning workflow for this app. Returns {id} by
            default; expand with expand=default_provisioning_workflow for the
            full workflow object. Omitted entirely if the caller lacks read
            access to AppStore item workflows.
        default_deprovisioning_workflow:
          anyOf:
            - $ref: '#/components/schemas/Workflow'
            - $ref: '#/components/schemas/WorkflowRef'
            - type: 'null'
          title: Default Deprovisioning Workflow
          description: >-
            The default deprovisioning workflow for this app. Returns {id} by
            default; expand with expand=default_deprovisioning_workflow for the
            full workflow object. Omitted entirely if the caller lacks read
            access to AppStore item workflows.
        appstore_settings:
          anyOf:
            - $ref: '#/components/schemas/AppStoreSettingsCompact'
            - $ref: '#/components/schemas/AppStoreSettingsResponse'
            - type: 'null'
          title: Appstore Settings
          description: >-
            AppStore membership and settings. Present when the caller has read
            access to AppStore items. Returns {in_app_store} by default; expand
            with expand=appstore_settings for the full settings object.
        custom_attributes:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/CustomAttribute'
              type: object
            - type: 'null'
          title: Custom Attributes
          description: >-
            Custom attributes configured on this app. Only present when
            expand=custom_attributes is requested.
        sync_status:
          anyOf:
            - type: string
              enum:
                - syncing
                - success
                - failed
            - type: 'null'
          title: Sync Status
          description: >-
            The state of this app's most recent sync: `syncing` while one is
            running, `success` or `failed` once it finished. Omitted when no
            sync result is recorded — the app has never synced, or was
            disconnected.
      type: object
      required:
        - id
      title: AppResponse
    ApiErrorEnvelope:
      properties:
        error:
          $ref: '#/components/schemas/ApiError'
          description: The error that caused this response.
      type: object
      required:
        - error
      title: ApiErrorEnvelope
      description: >-
        The V1 error response body. Every error nests under `error`, so an error
        body is

        recognizable by its shape, not only its status code.
    AdminAssignee:
      properties:
        id:
          type: string
          title: Id
          description: The UUID of the admin user or group.
        type:
          type: string
          enum:
            - user
            - group
          title: Type
          description: Whether this admin is a `user` or a `group`.
      type: object
      required:
        - id
        - type
      title: AdminAssignee
    Workflow:
      properties:
        id:
          type: string
          title: Id
          description: A UUID identifying this Workflow.
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: A name for this Workflow.
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: A description of this Workflow.
        type:
          type: string
          enum:
            - approval
            - approval-chain
            - entitlement-provisioning
            - entitlement-deprovisioning
            - account-provisioning
            - account-deprovisioning
          title: Type
          description: The kind of workflow.
        app_id:
          anyOf:
            - type: string
            - type: 'null'
          title: App Id
          description: UUID of the app this Workflow belongs to, if associated.
        steps:
          items:
            $ref: '#/components/schemas/WorkflowStepOutput'
          type: array
          title: Steps
          description: The ordered steps of the workflow.
      type: object
      required:
        - id
        - type
        - steps
      title: Workflow
      description: Response shape for a Workflow.
    WorkflowRef:
      properties:
        id:
          type: string
          title: Id
          description: UUID of the bound workflow.
      type: object
      required:
        - id
      title: WorkflowRef
      description: |-
        A reference to a bound workflow — shaped `{ "id": "..." }` so the path
        `<field>.id` is stable whether or not the field is expanded.
    AppStoreSettingsCompact:
      properties:
        in_app_store:
          type: boolean
          title: In AppStore
          description: Whether this app is visible in AppStore for config/management.
      type: object
      required:
        - in_app_store
      title: AppStoreSettingsCompact
    AppStoreSettingsResponse:
      properties:
        request_instructions:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Instructions
          description: >-
            Custom instructions shown to a requester when they open the
            access-request form. Null means no custom instructions are set.
        allow_permission_selection:
          type: boolean
          title: Allow Permission Selection
          description: >-
            When true, requesters may select which entitlement to request. When
            false, the default entitlement is used automatically and only
            approvers can change it. An app that was never configured reports
            the value Lumos applies when validating its access requests, which
            may be false.
        allow_multiple_permission_selection:
          type: boolean
          title: Allow Multiple Permission Selection
          description: >-
            When true, requesters may select more than one entitlement in a
            single request.
        allowed_requester_group_uuids:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Allowed Requester Group Uuids
          description: >-
            UUIDs of the groups whose members may request this app. Null means
            everyone in your organization can request the app.
        time_based_access:
          $ref: '#/components/schemas/TimeBasedAccess'
          description: Time-based access configuration for this app.
        request_validation_webhook_uuid:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Validation Webhook Uuid
          description: >-
            UUID of the inline webhook called to validate access requests before
            approval. Null means no validation webhook is configured.
        redirect_url:
          anyOf:
            - type: string
              maxLength: 2048
            - type: 'null'
          title: Redirect Url
          description: >-
            If set, requesting this app redirects the user to this URL instead
            of going through the normal access-request flow. Null means no
            redirect is configured. Max 2048 characters.
        default_entitlement:
          anyOf:
            - $ref: '#/components/schemas/EntitlementRef'
            - type: 'null'
          description: >-
            The entitlement pre-selected by default when a user opens the
            request form. Null means no default is set.
        custom_intake_fields:
          anyOf:
            - items:
                $ref: '#/components/schemas/CustomIntakeField'
              type: array
            - type: 'null'
          title: Custom Intake Fields
          description: >-
            Custom form questions shown to requesters before they submit an
            access request. Null means no custom fields are configured.
        in_app_store:
          type: boolean
          title: In AppStore
          description: Whether this app is listed in the AppStore catalog.
        catalog_visibility:
          type: string
          enum:
            - visible
            - search-only
            - hidden
          title: Catalog Visibility
          description: >-
            Visibility of the app within the catalog. "visible" — shown in
            browse and search; "search-only" — returned only by search, not in
            browse; "hidden" — enrolled but not visible to requesters.
      type: object
      required:
        - allow_permission_selection
        - allow_multiple_permission_selection
        - time_based_access
        - in_app_store
        - catalog_visibility
      title: AppStoreSettingsResponse
    CustomAttribute:
      properties:
        type:
          type: string
          enum:
            - text
            - user
            - single-select
          title: Type
          description: >-
            The type of custom attribute. Only text and user options are
            available today
        value:
          anyOf:
            - type: string
            - items:
                $ref: '#/components/schemas/User'
              type: array
            - type: string
              format: date-time
            - type: integer
            - type: 'null'
          title: Value
          description: The value of the attribute for an individual Order
      type: object
      required:
        - type
      title: CustomAttribute
    ApiError:
      properties:
        detail:
          type: string
          title: Detail
          description: Human-readable summary of the error.
        type:
          $ref: '#/components/schemas/ErrorType'
          description: >-
            Category:
            validation|authentication|permission|not_found|conflict|rate_limited|runtime.
        code:
          type: string
          title: Code
          description: Stable machine-readable error code; branch on this, not 'detail'.
        errors:
          items:
            $ref: '#/components/schemas/ApiErrorField'
          type: array
          title: Errors
          description: Field-level errors; empty for non-validation errors.
      type: object
      required:
        - detail
        - type
        - code
      title: ApiError
      description: The V1 error object — the contents of the envelope's `error` field.
    WorkflowStepOutput:
      properties:
        step:
          type: string
          title: Step
          description: Identifier (catalogue slug) for the step to execute.
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: Server-derived human-readable name for this step. Read-only.
        inputs:
          type: object
          title: Inputs
          description: The configured inputs for this step.
      type: object
      required:
        - step
        - inputs
      title: WorkflowStepOutput
      description: A single configured step in a workflow (response shape).
    TimeBasedAccess:
      properties:
        options:
          anyOf:
            - items:
                $ref: '#/components/schemas/TimeBasedAccessOption'
              type: array
            - type: 'null'
          title: Options
          description: >-
            Time-based access options available for this app. Null means the app
            uses your organization's defaults.
        default:
          anyOf:
            - type: string
            - type: 'null'
          title: Default
          description: >-
            Label of the option pre-selected when a user opens the request form.
            Null means no option is pre-selected.
      type: object
      title: TimeBasedAccess
    EntitlementRef:
      properties:
        id:
          type: string
          title: Id
          description: The UUID of the entitlement.
      type: object
      required:
        - id
      title: EntitlementRef
      description: >-
        Reference to an Entitlement embedded in another resource (e.g.
        AppStoreSettingsResponse).
    CustomIntakeField:
      properties:
        reference_key:
          type: string
          title: Reference Key
          description: >-
            Stable identifier for this field. It is unique within the app and
            cannot be changed.
        field_type:
          $ref: '#/components/schemas/CustomIntakeFieldType'
          description: The kind of input shown for this custom intake field.
        prompt:
          type: string
          title: Prompt
          description: The question shown to the requester.
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Additional guidance shown alongside the prompt.
        is_required:
          type: boolean
          title: Is Required
          description: Whether the requester must answer this field to submit a request.
        dropdown_options:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Dropdown Options
          description: >-
            Selectable options for this field. Present only when field_type is
            "dropdown".
      type: object
      required:
        - reference_key
        - field_type
        - prompt
        - is_required
      title: CustomIntakeField
    User:
      properties:
        id:
          type: string
          title: Id
          description: The ID of this user.
        email:
          anyOf:
            - type: string
            - type: 'null'
          title: Email
          description: The email of this user.
        given_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Given Name
          description: The given name of this user.
        family_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Family Name
          description: The family name of this user.
        status:
          anyOf:
            - type: string
              enum:
                - staged
                - active
                - suspended
                - inactive
            - type: 'null'
          title: Status
          description: The status of this user.
      type: object
      required:
        - id
      title: User
    ErrorType:
      type: string
      enum:
        - validation
        - authentication
        - permission
        - not_found
        - conflict
        - rate_limited
        - runtime
      title: ErrorType
    ApiErrorField:
      properties:
        field:
          type: string
          title: Field
          description: Input field this error refers to, e.g. 'steps[2].inputs.group_id'.
        code:
          type: string
          title: Code
          description: Stable machine-readable code for this field error.
        message:
          type: string
          title: Message
          description: Human-readable description of the field error.
      type: object
      required:
        - field
        - code
        - message
      title: ApiErrorField
      description: A single field-level error (used for validation failures).
    TimeBasedAccessOption:
      properties:
        label:
          type: string
          title: Label
          description: Display label for this time-based access option.
        value_seconds:
          anyOf:
            - type: integer
            - type: 'null'
          title: Value Seconds
          description: >-
            Duration in seconds. Null indicates a permanent (unlimited) access
            option.
      type: object
      required:
        - label
      title: TimeBasedAccessOption
    CustomIntakeFieldType:
      type: string
      enum:
        - text
        - dropdown
      title: CustomIntakeFieldType
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````