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

# The Workflow object

> Reusable definitions of the steps Lumos runs to approve, provision, or deprovision access, and how to discover valid steps.

A workflow is a reusable definition of the steps Lumos runs when someone gains or loses access. It
sets who approves a request, what Lumos creates to grant the access, and what it removes to take
the access away. Workflows are definitions, not runs. Creating one doesn't execute anything. It
becomes live when you bind it to an [app](https://docs.lumos.com/reference/v1/objects/app.md) or an
[entitlement](https://docs.lumos.com/reference/v1/objects/entitlement.md).

Each workflow field accepts only a workflow of the matching `type`, as
[Workflow types](#workflow-types) describes.

```json The Workflow object theme={null}
{
  "id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
  "name": "Manager approval, then IT",
  "description": "Two-stage approval for privileged roles.",
  "type": "approval-chain",
  "app_id": "2b3c4d5e-6f70-8901-bcde-f12345678901",
  "steps": [
    {
      "step": "approval_task",
      "name": "Access Request Approval",
      "inputs": {
        "stage_number": 1,
        "assignees": [{ "label": "Manager", "type": "custom_attribute_definition" }]
      }
    },
    {
      "step": "approval_task",
      "name": "Access Request Approval",
      "inputs": {
        "stage_number": 2,
        "assignees": [{ "uuid": "3c4d5e6f-7081-9012-cdef-123456789012", "type": "group" }]
      }
    }
  ]
}
```

## Attributes

| Field | Type | Description |
| - | - | - |
| `id` | string | Unique identifier for the workflow. Always present. |
| `name` | string or null | Display name. |
| `description` | string or null | Description of what the workflow does. |
| `type` | string | The kind of workflow, which decides where it can be bound. Always present, immutable. |
| `app_id` | string or null | The app this workflow belongs to, when it's scoped to one. Immutable. |
| `steps` | array | The ordered steps. Always present. See [Steps](#steps). |

## Workflow types

`type` is one of six values, and it determines which workflow field a workflow can be bound to:

| Type | Binds to |
| - | - |
| `approval` | An app's or entitlement's approval workflow. |
| `approval-chain` | An app's or entitlement's approval workflow, for multi-stage approval. |
| `entitlement-provisioning` | An entitlement's provisioning workflow. |
| `entitlement-deprovisioning` | An entitlement's deprovisioning workflow. |
| `account-provisioning` | An app's default provisioning workflow. |
| `account-deprovisioning` | An app's default deprovisioning workflow. |

Choose between account and entitlement workflows carefully. Account workflows create and remove
someone's account on an app. Entitlement workflows grant and remove one entitlement on it. A
workflow of the wrong type can't be bound where you need it.

`type` and `app_id` are both immutable. [Update Workflow](https://docs.lumos.com/api-reference/v1/workflows/update-workflow.md) rejects any attempt to change them, so a workflow of
the wrong type has to be recreated rather than converted.

## Steps

`steps` is an ordered list, and the order is the execution order. Each step is:

| Field | Type | Description |
| - | - | - |
| `step` | string | The catalog slug naming which step to run. |
| `inputs` | object | The configured inputs for this step. Shape depends on the step. |
| `name` | string or null | Human-readable name, derived by the server. Read-only. |

`name` is server-derived and read-only. Don't send it on create or update, and don't treat it as
a stable identifier. `step` is the identifier that matters.

### Branch steps

A `branch` step runs the first workflow whose condition matches the identity, or
`fallback_workflow_id` when none does. Send `inputs` in the form a read returns: `branches` as a
list of `{ "condition": …, "workflow_id": … }`, and an optional `fallback_workflow_id`. Name each
workflow by its `id`. Any other form returns `400`, and so does a workflow that belongs to a
different app.

Lumos checks each condition when you save the workflow, and returns `400` for one it can't
evaluate. `detail` names the branch, such as `branches[0].condition`. For what a condition can
test, see [Conditions](https://docs.lumos.com/reference/v1/guides/conditions.md).

### Approval workflows

`approval` and `approval-chain` workflows follow extra rules, and a write that breaks one returns
`400`:

* `app_id` is required.
* An `approval` workflow holds exactly one `branch` step. Each workflow its branches name, and its
  fallback, must be an `approval-chain` workflow.
* An `approval-chain` workflow holds only `approval_task` steps. Each step needs a `stage_number`
  and at least one assignee in `assignees`. Number the stages 1, 2, 3, and so on.
* You can't update an `approval-chain` workflow that more than one `approval` workflow uses.

When an update stops an `approval` workflow from using a chain, the chain isn't deleted.
[Delete Workflow](https://docs.lumos.com/api-reference/v1/workflows/delete-workflow.md) can't delete an `approval-chain`
workflow on its own, and returns `422` with `code` set to
`workflow.approval_chain_delete_not_supported`.

## Discover valid steps before building one

`inputs` is a free-form object whose required shape depends entirely on which `step` you chose.
Read the step catalog before you build `inputs`:
[List Workflow Steps](https://docs.lumos.com/api-reference/v1/workflows/list-workflow-steps.md) returns the catalog of steps
available for an app, each with the JSON Schema of its inputs. Pass `type` with the type of
workflow you'll create. Some steps work in only one type, and without `type` the catalog lists
every step that any type accepts, including steps the type you create refuses.

```bash theme={null}
curl -s 'https://api.lumos.com/v1/workflow-steps?app_id=2b3c4d5e-6f70-8901-bcde-f12345678901&type=account-provisioning' \
  --header 'Authorization: Bearer lsk_your_token'
```

Each entry carries `step`, an optional `name`, and `input_schema`, the schema of the inputs that step
accepts. Read `input_schema`, build `inputs` to match, then send the workflow.

An input that takes assignees, such as `assignees` on `approval_task`, has a `description` that
lists the forms each assignee can take. The forms an input accepts depend on the step. Examples are
`{ "type": "group", "uuid": "…" }`, `{ "type": "custom_attribute_definition", "label": "…" }`, and
`{ "type": "dynamic_assignee", "uuid": "app_admins" }`.

Steps available on one app aren't necessarily available on another, which is why the endpoint is
scoped by app.

## Creating and binding

Creation and binding are separate operations.
[Create Workflow](https://docs.lumos.com/api-reference/v1/workflows/create-workflow.md) stores a definition. The workflow
does nothing until it's bound to an app or entitlement:

**1. Find the steps you can use**

Call [List Workflow Steps](https://docs.lumos.com/api-reference/v1/workflows/list-workflow-steps.md) for the app and the
workflow `type`, and read each `input_schema`.

**2. Create the definition**

Call Create Workflow with a `type`, an ordered `steps` array, and the `inputs` each step's schema
asked for.

**3. Bind it to an app or entitlement**

`PUT` the workflow's ID into the workflow field you want it to govern. That field can be an app's
approval, default provisioning, or default deprovisioning workflow, or one of an entitlement's three
workflow fields. The workflow endpoints are listed on the
[App](https://docs.lumos.com/reference/v1/objects/app.md#endpoints) and
[Entitlement](https://docs.lumos.com/reference/v1/objects/entitlement.md#endpoints) pages.

A workflow can be bound to one app or entitlement. Binding returns `409` with `code` set to
`workflow.bind_conflict` when the workflow belongs to a different app, or another app or
entitlement already binds it. Binding a workflow again to the app or entitlement that already binds
it succeeds. A workflow of the wrong `type` returns `422` with `code` set to
`workflow.type_mismatch`.

[Delete Workflow](https://docs.lumos.com/api-reference/v1/workflows/delete-workflow.md) returns `409` while the workflow is
in use:

* `workflow.bound_delete_not_allowed` when it's an app's approval workflow, or an entitlement's
  approval, provisioning, or deprovisioning workflow. Bind another workflow in its place first, or
  remove an entitlement's approval workflow override.
* `workflow.default_delete_not_allowed` when it's an app's default provisioning or deprovisioning
  workflow.

Reading a workflow field returns `{ "id": … }` by default and the full workflow when you expand it.
Some bound workflows return only `{ "id" }` even when you expand them.

## Endpoints

| Endpoint | Path |
| - | - |
| [Create Workflow](https://docs.lumos.com/api-reference/v1/workflows/create-workflow.md) | `POST /v1/workflows` |
| [List Workflows](https://docs.lumos.com/api-reference/v1/workflows/list-workflows.md) | `GET /v1/workflows` |
| [Get Workflow](https://docs.lumos.com/api-reference/v1/workflows/get-workflow.md) | `GET /v1/workflows/{workflow_id}` |
| [Update Workflow](https://docs.lumos.com/api-reference/v1/workflows/update-workflow.md) | `PUT /v1/workflows/{workflow_id}` |
| [Delete Workflow](https://docs.lumos.com/api-reference/v1/workflows/delete-workflow.md) | `DELETE /v1/workflows/{workflow_id}` |
| [List Workflow Steps](https://docs.lumos.com/api-reference/v1/workflows/list-workflow-steps.md) | `GET /v1/workflow-steps` |
