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

# Lumos Connector API

## Introduction

The Lumos Connector API is a standardized interface for Identity and Access Management (IAM) operations across various third-party systems. It enables integration between Lumos and external applications by providing a consistent set of operations called **capabilities**.

Each integration (referred to as a "connector") implements these capabilities to work with different third-party API providers, focusing primarily on:

* User access management
* User activity monitoring

## Core Components

### Connectors

A connector is a specialized library that acts as a bridge between Lumos and third-party applications. It handles:

* Translation of Lumos requests into app-specific API calls
* Conversion of app-specific responses into standardized Lumos formats
* Authentication and authorization flows
* Data format transformations

### Capabilities

Capabilities are standardized operations that each connector can implement. They provide:

* Consistent interfaces across different connectors
* Predictable behavior patterns
* Standardized error handling
* Unified data structures

## Data Model

### Accounts

Accounts represent individual users or service accounts within a system.

They serve as the primary entities for access management and support lifecycle operations such as creation, activation, deactivation, and deletion.

Accounts can be associated with multiple entitlements and are typically identified by a unique account ID within the system.

### Entitlements

Entitlements represent a permission or capability that can be granted to user accounts, such as an access level.

They define specific permissions, access rights, or memberships and are always associated with a resource, which may be global or specific.

Entitlements are categorized by **entitlement\_type** (e.g., roles, permissions, group memberships) and have defined constraints for minimum and maximum assignments.

The naming of entitlements may vary, such as using "membership" for group associations.

### Resources

Resources represent entities within an application that can be accessed or managed.

They are identified by a unique **resource\_type** within each app and include a global resource (represented by an empty string) for top-level entities.

Resources can represent hierarchical structures, such as Workspaces containing Users and Groups, and serve as the context for entitlement assignments.

The usage of Resource IDs depends on the specific hierarchy, with an empty string for global resources and specific IDs (e.g., Workspace ID) for nested resources.

### Associations

Associations define relationships from accounts to entitlements (which are resource specific).

They follow a hierarchical structure of Account -> Entitlement -> Resource, with no direct account-to-resource associations allowed.

Associations enable flexible access control models.

Note: The specific structure and use of resources and entitlements may vary depending on the integrated system's architecture and access model.

## How to Use This API

1. Discover available connectors
2. Learn about a specific connector
3. Configure a connector
4. (optional) Authenticate with OAuth
5. Read data from the connected tenant
6. Write (update) data in the connected tenant

## Authenticating with a Connector

### The Credentials Model

A single connection to an app may require **more than one credential**. A connector might, for example, use OAuth for the app's REST API and a separate SCIM token for user provisioning.

To support this, every connector declares the full set of credentials it accepts. Each credential has:

* A stable **credential ID** unique within the app (e.g. `lucid_oauth`, `lucid_scim`)
* An **authentication model** describing its shape (OAuth, token, basic, JWT, and so on)
* **Setup instructions** shown to the person configuring the connection
* An **optional** flag, for credentials the connector can operate without (usually at a reduced scope)

Requests then carry a `credentials` array, where each entry is tagged with the ID it was declared under:

```json theme={null}
{
  "credentials": [
    {
      "id": "lucid_oauth",
      "oauth": { "access_token": "..." }
    },
    {
      "id": "lucid_scim",
      "token": { "token": "..." }
    }
  ],
  "request": {},
  "settings": { "team_id": "123456" }
}
```

The key inside each entry (`oauth`, `token`, `basic`, `jwt`, `service_account`, `key_pair`, `oauth_client_credentials`, `oauth1`) matches that credential's authentication model.

> **Legacy single-credential connectors.** Older connectors accept exactly one credential and receive it on a single `auth` object instead of the `credentials` array. Both shapes are supported, a connector's schema (below) tells you which one it uses.

### Authentication Models

| Authentication model | Request key | Typical use |
| - | - | - |
| OAuth 2.0 | `oauth` | Authorization code flow (3-legged) |
| OAuth 2.0 Client Credentials | `oauth_client_credentials` | Machine-to-machine (2-legged) |
| OAuth 1.0 | `oauth1` | Legacy OAuth 1.0a APIs |
| Token | `token` | API keys and bearer tokens |
| Basic Auth | `basic` | Username and password |
| JWT | `jwt` | JWT-based auth |
| Service Account | `service_account` | Service account key files |
| Key Pair | `key_pair` | Public/private key pairs (e.g. Snowflake) |

### OAuth-based Authentication

The API supports two OAuth flow types. When a connector declares more than one OAuth credential, pass `credential_id` on each OAuth request so the connector knows which credential the request applies to.

#### Authorization Code Flow (3-legged OAuth)

Requires a multi-step flow:

1. **Authorization URL**

* Call **get\_authorization\_url** to start the OAuth flow
* Redirect user to the returned authorization URL

2. **Handle Callback**

* Process the OAuth callback using **handle\_authorization\_callback**
* Receive access and refresh tokens

3. **Token Management**

* Use **refresh\_access\_token** to maintain valid access
* Store refresh tokens securely

#### Client Credentials Flow (2-legged OAuth)

Suitable for machine-to-machine authentication:

1. **Direct Token Request**

* Call **handle\_client\_credentials\_request** with client credentials
* Receive access token (and optionally refresh token)

2. **Token Management**

* Use **refresh\_access\_token** to maintain valid access (if refresh tokens are supported)
* Store tokens securely

The flow type is configured per credential and determines which capabilities are available. Both flows support customizable authentication methods (Basic Auth or request body) and different request formats (JSON, form data, or query parameters).

### Validation

Validation happens at two points, and the two are deliberately different.

#### 1. Per-credential validation, while configuring

Call **validate\_credential\_config** with a single credential to check it before the connection is saved. This is a fast check — it confirms the credential is well-formed (required fields present, no stray whitespace, expected prefix or length, allowed scopes are granted on an access\_token, etc.) and returns customer-facing messages explaining anything that is wrong.

```json theme={null}
{
  "request": {
    "credential": {
      "id": "lucid_api_key",
      "token": { "token": "key-123456" }
    }
  },
  "settings": { "team_id": "123456" }
}
```

The response reports validity plus any errors to display:

```json theme={null}
{
  "response": {
    "valid": false,
    "validation_errors": [
      "Invalid API key format. Lucid API keys must start with 'key-'."
    ]
  }
}
```

This capability is available on every connector that uses the credentials model.

#### 2. Connection validation, against the live API

Call **validate\_credentials** with the full set of credentials to prove they actually work:

1. The connector makes a real, lightweight authenticated request to the app
2. On success it returns the unique tenant ID for the authenticated organization

### Authentication Schema

Each connector publishes the credentials it accepts, so a configuration UI can be built from it without app-specific knowledge.

* `info.credentials_schema` — an array with one JSON Schema entry per credential the connector accepts. Each entry carries:
  * `id` — the credential ID to send back in the `credentials` array
  * `description` — markdown setup instructions for the customer
  * `x-optional` — whether the connector can run without this credential
  * `x-credential-type` — the authentication model, and therefore the request key to nest the payload under (`oauth`, `token`, …)
  * `properties`, `required` and `field_order` — the credential's fields, their order, and which are secret or hidden
* `info.authentication_schema` — used only by legacy single-credential connectors, and empty for connectors using the credentials model. Where it is populated, `credentials_schema` is empty, and vice versa — so you can use whichever is non-empty to detect which shape a connector uses.

The connector's OpenAPI document (from **app\_info**) carries the same per-credential schemas under `components.securitySchemes`, keyed by credential ID, each with an additional `x-credential-name` display label. It additionally exposes `info.x-allowed-credentials`: the list of credential-ID combinations that form a valid connection. For example:

```json theme={null}
"x-allowed-credentials": [
  ["lucid_oauth", "lucid_scim"],
  ["lucid_oauth", "lucid_scim", "lucid_api_key"]
]
```

This connector can be configured either with OAuth plus a SCIM token, or with those two plus an optional API key that unlocks license entitlements. Any combination not listed is not a valid configuration.

## Pagination

Lumos connectors implement a standardized pagination mechanism to handle large datasets efficiently. The pagination system uses opaque tokens to maintain state across requests.

### How Pagination Works

1. **Request Format** Every request can include an optional **page** parameter:

```
{
     "page": {
       "token": string,  // Optional: opaque token from previous response
       "size": number    // Optional: number of items per page
     }
   }
```

<br />

1. **Response Format** Paginated responses include a **page** field:

```
 {
     "response": T[],    // Array of items
     "page": {
       "token": string,  // Token for the next page
       "size": number    // Items per page
     }
   }
```

<br />

### Using Pagination

1. **Initial Request**

* Make the first request without a page token
* Optionally specify a page size

1. **Subsequent Requests**

* Include the **token** from the previous response
* Keep the same page size for consistency

1. **End of Data**

* When there's no more data, the response won't include a page token

### Example Flow

```http HTTP theme={null}
// First request
POST /connectors/pagerduty/list_accounts
{
  "page": { "size": 100 }
}

// Response
{
  "response": [...],
  "page": {
    "token": "eyJwYWdlIjogMn0=",
    "size": 100
  }
}

// Next request
POST /connectors/pagerduty/list_accounts
{
  "page": {
    "token": "eyJwYWdlIjogMn0=",
    "size": 100
  }
}
```

<br />

### Implementation Notes

* Page tokens are opaque and should be treated as black boxes
* Tokens may encode various information (page numbers, cursors, etc.)
* The same page size should be used throughout a pagination sequence
* Invalid or expired tokens will result in an error response
