github.com is an integration. When your organization connects GitHub, the result is
an app. If you connect the same integration twice, for example to a production tenant and to a
sandbox, you have two apps, and instance_id tells them apart.
Almost everything else in v1 belongs to an app. Its
entitlements are the units of access you can grant on it. Its
accounts are the user, role, and service accounts that exist on
it. The three workflows bound to it decide what Lumos does when
someone requests access to it.
The App object
Attributes
Absent and null fields
The response omits fields that have no value instead of returning them asnull. An app with no
description has no description key at all, so read the object with .get() semantics rather
than expecting every field in the table above.
Three exceptions break that rule on purpose:
- The response includes the five
*_overridefields asnullwhen they aren’t set. - The response includes the three workflow fields as
nullwhen no workflow is bound. It omits one only when you can’t read it. - The response omits
appstore_settingsentirely when you can’t read it, instead of returning it empty.
expand.
An expanded appstore_settings keeps its own fields that have no value, as null. It matches what
Get AppStore Settings returns.
Display fields
label, logo_url, website_url, category, and description are what people see. Each one
shows its *_override field when your organization set one, and the app’s default otherwise. They’re
read-only, so a create or update body that sends one returns 400. Write the *_override
fields instead, as Update metadata or credentials describes.
The overrides change only your organization’s copy of the app, not the shared Lumos catalog. Lumos
stores each one exactly as you send it, even when it matches the default, so a later change to the
default doesn’t change what you read back.
Bound workflows
Every app has three workflow fields:approval_workflow, default_provisioning_workflow, and
default_deprovisioning_workflow. Each holds a reference to the bound workflow, or null when none
is bound.
expand to get the full workflow definition inline instead of the
reference.
Each workflow field has its own permission check. Of the built-in roles, Admin, Read Only Admin,
and AppStore Read Only Admin can read all three fields on every app, and App Admin can read them
on the apps they administer. A workflow field you can’t read is absent, as
Absent and null fields describes.
To read or change which workflow is bound, use that field’s own workflow endpoints, listed under
Endpoints, rather than sending the whole app object.
Expanding fields with expand
Reads return the base object. Pass expand to include fields that reads omit by default:
admins, approval_workflow, default_provisioning_workflow,
default_deprovisioning_workflow, custom_attributes, and appstore_settings.
A field you can’t read is omitted rather than failing the request, as
Requesting fields with expand describes.
admins
admins is an array of user and group references. Expanding it on an app with no admins returns an
empty array, not a missing key.
422 with code set to user.not_found or group.not_found.
An app needs at least one admin before you add it to the AppStore. Setting in_app_store to true
on an app with no admins returns 409 with code set to app.admin_required, so set the admins
first. Removing the last admin doesn’t take a listed app out of the AppStore.
custom_attributes
custom_attributes is an object keyed by attribute label. Each value carries its own type, one
of text, user, or single-select. An app with no custom attributes configured may omit the key even when you
expand it.
appstore_settings
appstore_settings contains only in_app_store unless you expand it. Expanded, it returns the full
settings object that AppStore settings describes.
Get AppStore Settings returns the same fields on
their own. Use it when you need only the settings.
AppStore settings
Update AppStore Settings is a merge patch that takes these fields. Every field is optional, and a field you omit keeps its value.null clears a
field, except for four that always hold a value: in_app_store, catalog_visibility,
allow_permission_selection, and allow_multiple_permission_selection. null on one of them
returns 400. A value you send for a list field replaces the whole list.
Time-based access
time_based_access has two fields:
422 with
code set to time_based_access.unknown_option. New
organizations start with options such as 7 days, 30 days, and Unlimited. Your organization’s
default options are the subset of its options that an app offers when it has no list of its own.
Sending options pins that list on the app, so later changes to your organization’s default
options no longer apply to it. Send default together with options. While the app uses your
organization’s default options, a default sent alone returns 422 with code set to
time_based_access.default_not_offered. To return to your
organization’s default options, send both as null.
When you read the settings, options is null while the app uses your organization’s default
options. Otherwise each option carries a label and a value_seconds, which is null for a
duration with no end.
Custom intake fields
Each item incustom_intake_fields describes one question:
reference_key, updates the
ones you send, and deletes the ones you omit. null or an empty list deletes them all. A list that
breaks these rules returns 400 with code set to appstore_settings.custom_intake_fields_invalid.
errors lists every problem by position, such as custom_intake_fields[2].reference_key. 409
means another call used the same reference_key at the same time.
Entitlement selection
allow_permission_selection decides whether requesters pick an entitlement:
- With
true, they choose from the app’s visible entitlements, andallow_multiple_permission_selectiondecides whether they can choose more than one. - With
false, they can’t choose. A request gets the app’sdefault_entitlement, or no entitlement when none is set.
default_entitlement must be one of this app’s entitlements, and it must have AppStore settings.
Otherwise the call returns 422 with code set to entitlement.wrong_app or
entitlement.not_requestable. Entitlements from
Create Entitlement always have them.
Request validation
Forrequest_validation_webhook_uuid, use the id of an
inline webhook whose type is request-validation, from
List Inline Webhooks. A webhook of
another type returns 422 with code set to request_validation_webhook.wrong_type.
The app’s webhook checks requests that don’t name an entitlement. For a request that names
entitlements, Lumos calls each entitlement’s own webhook instead of the app’s, so set a webhook on
each entitlement too, as AppStore settings
on the Entitlement object describes.
Syncs and their status
sync_status reports the state of the app’s most recent sync, not the health of the app’s
credentials. It moves from syncing to success or failed. sync_status is absent when Lumos
has no sync result for the app, for example because the app has never synced or was disconnected.
An absent sync_status doesn’t mean that a sync failed.
Trigger App Sync starts a sync and returns 202 with an
operation instead of waiting for the sync to finish. sync_type is required, and full-sync is the
only value it accepts today. Any other value returns 400.
Response
id until
done is true, as Long-running operations describes.
At that point the operation carries result if the sync succeeded, or error with code set to
app_sync.failed if it failed. The operation is a view of the app’s latest sync rather than a
record of one run, and it reads the same state as sync_status.
Only one sync runs per app at a time. If you request a sync while another sync is running on the
app, Lumos returns 409 with code set to app.sync_in_progress. Lumos doesn’t queue the second request.
The first sync
A newly connected app’s first sync waits for a review of its identity matching rules, which decide the Lumos user that each of the app’s accounts belongs to. Without custom rules, Lumos matches accounts to users by email address. Until that sync starts, the app has no synced accounts or entitlements, and Trigger App Sync withoutskip_first_sync_review returns 409. Of the built-in roles, only Admin can start that sync, and a
custom role can also allow it. Start the first sync in one of two ways:
- In the Lumos UI, after reviewing the rules.
- With Trigger App Sync and
skip_first_sync_review: true, which starts it without the review.
Creating, updating, disconnecting, and deleting apps
Each of these four operations has its own endpoint:- Create or connect. Create App returns
201with the new app. - Update or reconnect. Update App returns
200with the updated app. Sending credentials reconnects it. - Disconnect. Disconnect App removes the stored
credentials and returns
200with the app’sid, itsapp_class_id, anddisconnected: true. Reconnect it later by sending credentials to Update App. - Delete. Delete App removes the stored credentials in
every case. For a custom app, it deletes the app together with its AppStore settings, admins, and
custom attributes, and returns
204. If the app still has accounts, or other Lumos data still references it, the call returns409withcodeset toapp.delete_blocked, and the app stays in a disconnected state. An app connected through an integration is disconnected during the call, which returns202with an operation. Lumos then deletes its record in the background.
200 either way.
Delete tells you which happened. For a custom app, 204 means the app is gone, and 409 means
it’s still readable in a disconnected state. detail says whether accounts or other data kept it.
After you remove its accounts, Delete can return 409 for a short time, until Lumos updates the
app’s account count. For an app connected through an integration, poll the operation until done
is true, as Long-running operations describes.
Disconnect, delete, and credential updates work only on apps connected through the API.
List Apps
returns these apps for connection_source=api. Any other app returns 409. An app created in the
Lumos UI stays managed in the UI, so automation can’t overwrite its credentials. Metadata updates
work on any app.
Create a custom app or connect an integration
Create App takes one of two bodies:- Connect an integration with
app_class_id, the credentials inauth, and any non-secret configuration insettings. The keys vary by integration, so read them from Get Integration Connection Schema rather than hardcoding them. Credentials that validate right away connect the app. Its first sync then waits for a review of the app’s identity matching rules, or for you to start it without the review, as The first sync describes. - Create a custom app with
label_override,category_override, anddescription_override, and either noapp_class_idorapp_class_idset tocustom. A custom app is an app that Lumos has no integration for, so you maintain its accounts yourself, for example with Upload Accounts. It reportsapp_class_idascustom, so you can send back a body you read.
logo_url_override, website_url_override, request_instructions, and
post_approval_message, and connecting an integration can set the other overrides too. A body that
sends auth, settings, or version without an integration’s app_class_id returns 400.
For an integration that needs browser consent, send auth: {} and finish connecting it in the
Lumos UI. The API can’t connect the integrations below at all, and returns 422 with code set to
app.api_unsupported for them:
- a CSV/flatfile app
- an integration whose
authorsettingsfields the API doesn’t support yet
409 with code set
to app.on_prem_connector_unavailable. Install the connector on an agent, then retry.
Create a custom app
Update metadata or credentials
Update App treats two groups of fields differently:-
Metadata (
label_override,category_override,description_override,logo_url_override,website_url_override,request_instructions,post_approval_message) is merge-patched. An omitted field keeps its value.nullclears an override, so the matching display field shows the app’s default again. A custom app has no default name, description, or category, sonullfor one of those three returns422withcodeset toapp.field_not_clearable.- An override can’t be empty.
label_overridetakes up to 255 characters,description_overrideup to 1,000, and the two URLs up to 2,048. request_instructionsignoresnull, so this endpoint can’t clear it.post_approval_messagetakes up to 511 characters. It has no default, sonullremoves it, and an app with no message omits the field.""returns400.
-
Credentials (
auth,settings,version) are one group. Lumos replaces the group instead of merging it, soauthis required whenever you sendsettingsorversion. A body withoutauthreturns400, and the stored credentials don’t change. Sending any of the three reconnects the app with exactly what you sent. Lumos re-validates the credentials and starts a sync. If the app has never completed a sync, that sync waits for review, as The first sync describes. For an integration that needs browser consent, the reconnect waits for that consent in the Lumos UI.
409 with code
set to app.sync_in_progress. The Retry-After header gives the wait in seconds.
Reconciling apps connected through the API
GET /v1/apps takes a disconnected filter, because a disconnected app can stay readable. Pair
disconnected=false with connection_source=api to reconcile only the apps connected through the
API:
AppStore catalog view
Get AppStore Catalog is the requester view of your AppStore, and it deliberately returns less than the object above: no workflow fields, nopost_approval_message, no admins, no custom_attributes, and no sync_status. Its
appstore_settings is scoped to what a requester needs to see.
Don’t write code that treats the two shapes as interchangeable. If you need the admin view of an
app, fetch it by ID.
Endpoints
Every app ID in these paths is the
id field of the object above.