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

# Create App

> Create a new custom app, or connect an integration app.

With a `name`/`category`/`description` body this creates a custom app. With an `app_class_id` body it connects the integration identified by `app_class_id` using the credentials in `auth` — integrations that validate in-band connect immediately and trigger an initial sync, while integrations that require browser consent are finished in the Lumos UI. Custom apps and integrations created here are both marked `connection_source=API`; list your API-managed apps with `GET /apps?connection_source=API&disconnected=false`.



## OpenAPI

````yaml openapi/lumos.json POST /apps
openapi: 3.1.0
info:
  title: Lumos
  description: |2

        The Lumos API gives you the building blocks to administer and extend Lumos programmatically.
        Our REST API provides a management interface for the AppStore and a read interface
        for the Lumos Core.
        Go to https://developers.lumos.com to see our complete documentation.
  version: 0.1.0
servers:
  - url: https://api.lumos.com
security: []
tags:
  - name: Access Reviews
    description: >

      Create and manage access review campaigns — scheduled reviews of who has
      access to what

      across your connected apps.


      **Typical workflow for creating a review:**


      1. `GET /apps` — find the domain app UUIDs you want to review.

      2. `GET /access_reviews/scope_options?domain_app_id={id}` — discover
      available scope
         filters (employment status, team, last login, etc.). Each returned `items` entry is a
         ready-to-POST `scope_filters` payload; datetime and custom-attribute groups instead
         expose a `filter_input_template`.
      3. `POST /access_reviews` with `apps` (optionally with `scope_filters` per
      app) —
         creates the campaign.
      4. `GET /access_reviews/{id}` — poll until `status` transitions from
      `IN_PREPARATION`
         to `IN_PROGRESS`.

      **After creation:**


      - `POST /access_reviews/{id}/apps` — add more apps while `status !=
      COMPLETED`.

      - `PATCH /access_reviews/{id}` — update name / deadline / owner, or
      per-ARDA
        `scope_filters` and removal action.
      - `DELETE /access_reviews/{id}` — soft-delete the whole campaign.

      - `DELETE /access_reviews/{id}/apps/{arda_id}` — soft-delete a single app
      from the
        campaign.

      All endpoints require an API token with the `access_reviews.create` or

      `access_reviews.view` permission (Access Review Administrator or App Admin
      role).
  - name: Tasks
    description: >

      **Tasks** are work items emitted by Lumos workflows — things that need a
      human (or an

      automated caller) to make a decision or perform a step before the workflow
      can proceed.

      Typical examples:


      - An access request is waiting on an approver's decision.

      - A provisioning or deprovisioning step needs manual fulfillment.

      - An error needs acknowledgement.


      Each task carries two classification fields you can filter on:


      - **`task_category`** — what kind of decision or step the task represents.
      Values:
        `APPROVAL`, `PROVISIONING`, `DEPROVISIONING`, `ERROR`.
      - **`product_area`** — which Lumos product surface emitted the task.
      Values:
        `APPSTORE`, `ACCESS_REVIEWS`, `MOVER`, `ATTRIBUTE_SYNC`, `OFFBOARDING`, `ONBOARDING`,
        `PLATFORM`, `SAVINGS`.

      ### Which endpoint should I call?


      - **To approve or deny an access request**, use `POST
      /tasks/{task_id}/complete`
        (approve) or `POST /tasks/{task_id}/dismiss` (deny).
      - **To find pending approval tasks**, call
        `GET /tasks?task_category=APPROVAL&product_area=APPSTORE&status=PENDING` (access
        requests).
      - **Only use `POST /tasks/{task_id}/perform-action`** for tasks that
      expose custom workflow
        actions. Discover those actions via `GET /tasks/{task_id}/actions`. Approval tasks do not
        require this endpoint — `complete` and `dismiss` are the right primitives.

      For a full walkthrough with `curl` and Python examples, see the

      [Tasks API How-To](https://developers.lumos.com/docs/tasks-api-how-to)
      guide.
  - 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, or
      generate a Terraform

      resource, without hardcoding one credential shape per integration.
      Integrations whose connection

      schema Lumos cannot describe yet return 404.
  - 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
         start an initial sync. Apps that need browser consent are finished in the Lumos UI.
      3. `GET /v1/apps/{app_uuid}` to follow `sync_status`.

      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 `PUT /v1/apps/{app_uuid}`. `DELETE
      /v1/apps/{app_uuid}` drops the stored

      credentials and returns the app to a connectable state.


      ### Reading apps


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

      `appstore_settings`, or any of the three workflow slots. 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 reconcile the apps you manage from automation such as Terraform,
      combine

      `connection_source=API` with `disconnected=false`.


      ### Workflow slots


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

      default deprovisioning workflow. The two `default_` slots supply the
      workflow that entitlements on

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

      endpoints.
  - name: Entitlements
    description: >

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

      permission. 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}` renames it. `label` is the
      only field you can change
        today, and 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


      Three slots bind a workflow to a single entitlement rather than to the
      whole app: an approval

      override, a provisioning workflow, and a deprovisioning workflow. Each has
      a GET and a PUT.


      Not every entitlement supports them. An entitlement with no request
      configuration behind it

      returns 404 with `Workflows are not available for this entitlement.` on
      all six.
  - 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: 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}` to discover the steps
      available for that app, each
         with the input schema it 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}` rejects changes 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 a slot returns 400.
  - name: Custom Attribute Definitions
    description: >

      Custom attributes are the extra fields your organization keeps on users
      and accounts. 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 `config_type` to separate user
      attributes from account

      attributes, 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.
  - 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` archives rather than destroys. The entry stops appearing in list
      results and stays

      recoverable.


      Pages here are small: `page_size` defaults to 10 and is clamped to 25.
paths:
  /apps:
    post:
      tags:
        - Core
      summary: Create App
      description: >-
        Create a new custom app, or connect an integration app.


        With a `name`/`category`/`description` body this creates a custom app.
        With an `app_class_id` body it connects the integration identified by
        `app_class_id` using the credentials in `auth` — integrations that
        validate in-band connect immediately and trigger an initial sync, while
        integrations that require browser consent are finished in the Lumos UI.
        Custom apps and integrations created here are both marked
        `connection_source=API`; list your API-managed apps with `GET
        /apps?connection_source=API&disconnected=false`.
      operationId: createApp
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppInputCreate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/App'
        '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.
        '403':
          description: >-
            Forbidden — the caller lacks permission to manage apps on this
            domain.
        '404':
          description: >-
            Not found — no integration with this `app_class_id` is available to
            your domain.
        '409':
          description: Conflict — an instance for this app already exists in the domain.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '501':
          description: Not implemented — this app does not support the requested operation.
        '502':
          description: >-
            Bad gateway — the third-party service rejected the credentials, or
            the post-connect sync failed.
      security:
        - HTTPBearer: []
components:
  schemas:
    AppInputCreate:
      properties:
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: >-
            The name of the app you're creating. Required when creating a custom
            app.
        category:
          anyOf:
            - type: string
            - type: 'null'
          title: Category
          description: >-
            The category of the app you're creating; required when creating a
            custom app. 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'
        description:
          anyOf:
            - type: string
              maxLength: 8192
            - type: 'null'
          title: Description
          description: >-
            The description of the app you're creating. Required when creating a
            custom app.
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
          description: The URL of the logo of the app you're creating.
        website_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Website Url
          description: The URL of the website of the app you're creating.
        request_instructions:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Instructions
          description: The request instructions.
        app_class_id:
          anyOf:
            - type: string
            - type: 'null'
          title: App Class Id
          description: >-
            Canonical identifier of an integration to connect, e.g. `okta.com`.
            Providing it switches this request from creating a custom app to
            connecting that integration using `auth`/`settings`. Must be an
            integration Lumos supports for your domain; an unknown value is
            rejected with 400.
        auth:
          anyOf:
            - type: object
            - type: 'null'
          title: Auth
          description: >-
            Credentials for the integration being connected, as a JSON object —
            **all secrets go here**. The accepted keys depend on the integration
            and are validated server-side. Some integrations connect in-band
            from these credentials (e.g. an `api_key`, or an OAuth
            `client_id`/`client_secret`); others require browser consent and are
            finished in the Lumos UI — for those, send `{}`. Missing or
            wrong-shaped credentials are rejected with 400; credentials the
            third party rejects return 502. Only used with `app_class_id`.
        settings:
          anyOf:
            - type: object
            - type: 'null'
          title: Settings
          description: >-
            Non-secret configuration for the integration being connected, as a
            JSON object — e.g. host, port, region, or tenant / instance URL. The
            accepted keys vary by integration and some integrations need none.
            Only used with `app_class_id`.
        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 used
            with `app_class_id`.
      type: object
      title: AppInputCreate
      description: >-
        Body of `POST /apps`: create a custom app, or connect an integration.


        One flat model serves both operations (a request-body union would
        generate

        poorly into SDK/Terraform clients). Providing `app_class_id` switches
        the

        request from "create a custom app" to "connect an integration"; the
        model

        validator enforces the fields each mode requires.
      examples:
        - category: Engineering
          description: Hand-rolled deploy dashboard.
          name: My internal tool
        - app_class_id: okta.com
          auth:
            api_key: 0123456789abcdef0123456789abcdef
          settings:
            app_instance_identifier: myorg.okta.com
    App:
      properties:
        id:
          type: string
          title: Id
          description: The ID of this app.
        app_class_id:
          type: string
          title: App Class Id
          description: >-
            The non-unique ID of the service associated with this requestable
            permission. Depending on how it is sourced in Lumos, this may be the
            app's name, website, or other identifier.
        instance_id:
          type: string
          title: Instance Id
          description: >-
            The non-unique ID of the instance associated with this app. This
            will be the Okta app id if it’s an Okta app, or will be marked as
            custom_app_import if manually uploaded into Lumos.
        user_friendly_label:
          type: string
          title: User Friendly Label
          description: The user-friendly label of this app.
        status:
          $ref: '#/components/schemas/DomainAppStatus'
          description: >-
            The status of this app. Possible values: 'DISCOVERED', 'IN_REVIEW',
            'NEEDS_REVIEW', 'APPROVED', 'BLOCKLISTED', 'DEPRECATED'
        sources:
          items:
            $ref: '#/components/schemas/DiscoverySource'
          type: array
          title: Sources
          description: The sources of this app.
        allow_multiple_permission_selection:
          type: boolean
          title: Allow Multiple Permission Selection
          description: >-
            Determines whether users can request multiple permissions at
            once.This field will be removed in subsequent API versions.
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
          description: The URL of the logo of this app.
        website_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Website Url
          description: The URL of the website of this app.
        request_instructions:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Instructions
          description: The request instructions.
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: The user-facing description of the app
        category:
          anyOf:
            - type: string
            - type: 'null'
          title: Category
          description: The category of the app, as shown in the AppStore
        disconnected:
          type: boolean
          title: Disconnected
          description: >-
            Whether this app has been disconnected (its stored credentials
            removed via `DELETE /apps/{app_id}`). A disconnected app is excluded
            from `GET /apps?disconnected=false`; reconnect it with `PUT
            /apps/{app_id}`.
        links:
          $ref: '#/components/schemas/AppLinks'
          description: A collection of URLs related to this application
        sync_status:
          anyOf:
            - $ref: '#/components/schemas/SyncStatus'
            - type: 'null'
          description: >-
            The state of this app's most recent sync: `SYNCING` while one is
            running, `SUCCESS` or `FAILED` once it finished. Poll this after
            `POST /apps/{app_id}/sync` to follow that sync. `null` when no sync
            result is recorded — the app has never synced, or was disconnected.
      type: object
      required:
        - id
        - app_class_id
        - instance_id
        - user_friendly_label
        - status
        - sources
        - allow_multiple_permission_selection
        - disconnected
        - links
      title: App
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    DomainAppStatus:
      type: string
      enum:
        - DISCOVERED
        - IN_REVIEW
        - NEEDS_REVIEW
        - APPROVED
        - BLOCKLISTED
        - DEPRECATED
      title: DomainAppStatus
    DiscoverySource:
      type: string
      enum:
        - GSUITE_QUICK_INBOX
        - GSUITE_DEEP_INBOX
        - MICROSOFT_DEEP_INBOX
        - MICROSOFT_OAUTH
        - MICROSOFT_GCC
        - GSUITE_OAUTH
        - OKTA
        - MANUAL
        - ONELOGIN
        - ATLASSIAN
        - GOOGLE_CLOUD
        - LUMOS_INTEGRATION
        - JUMPCLOUD
        - CUSTOM
        - MCP
      title: DiscoverySource
    AppLinks:
      properties:
        self:
          type: string
          title: Self
          description: The canonical API URL for retrieving this specific application
        admin_url:
          type: string
          title: Admin Url
          description: A URL to access this application within the Lumos web UI
      type: object
      required:
        - self
        - admin_url
      title: AppLinks
    SyncStatus:
      type: string
      enum:
        - SYNCING
        - SUCCESS
        - FAILED
      title: SyncStatus
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````