> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livingsecurity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SCIM API reference and limits

> Endpoints, authentication, filters, sorting, pagination with cursors, PATCH paths, ETags, Bulk and rate limits of the Living Security SCIM 2.0 API.

> [!NOTE]
>
> **Which SCIM setup applies to you?** These pages describe **Living Security SCIM**. Open the SCIM card in your settings. If the card shows **Set up SCIM**, or its **Mode** row says **Native SCIM**, these pages apply. If **Mode** says **Current SCIM**, your organization still uses the earlier SCIM setup. An admin can move it: see [Move from the earlier SCIM setup](https://docs.livingsecurity.com/features/settings/scim/connection.md#move-from-the-earlier-scim-setup). If the card says SCIM is set up and managed in the setup wizard, use [SCIM Provisioning](https://docs.livingsecurity.com/features/settings/scim.md).

Living Security SCIM implements SCIM 2.0 ([RFC 7643](https://www.rfc-editor.org/rfc/rfc7643) and [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644)) and cursor pagination ([RFC 9865](https://www.rfc-editor.org/rfc/rfc9865)). Identity providers (IdPs) use it. You do not need to call it yourself to provision people.

## Base URL

`https://api.<region>.livingsecurity.ai/scim/v2`, where `<region>` is your organization's data residency region, for example `us-east-1`, `eu-west-1`, `ap-south-1` or `ap-south-2`. Copy it from the SCIM card. See [Regional base URLs](https://docs.livingsecurity.com/features/settings/scim/overview.md#regional-base-urls).

* Request bodies use `application/scim+json` or `application/json`, in UTF-8.
* Responses use `application/scim+json; charset=utf-8`.
* Every response has an `X-Request-Id` header. Living Security creates it. Give it to support when you ask about a request.

## Authentication

Send exactly one `Authorization` header.

| Method | Header | Notes |
| - | - | - |
| Bearer token | `Authorization: Bearer lsscim_...` | Created on the SCIM card. The default. |
| HTTP Basic | `Authorization: Basic <base64 of username:password>` | HTTPS only. Not on the SCIM card; ask Living Security support. |
| OAuth 2.0 client credentials | `Authorization: Bearer <access token>` | The access token must carry the `scim:provision` scope and belong to your organization. Not on the SCIM card; ask Living Security support. |

A connection accepts only the methods enabled for it. `GET /ServiceProviderConfig` lists them. Every refused credential gets the same `401` ([LS-SCIM-1001](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1001)) with `WWW-Authenticate: Bearer realm="scim"`.

## Endpoints

Every endpoint needs authentication, discovery included.

| Method | Path | What it does |
| - | - | - |
| `GET` | `/ServiceProviderConfig` | The features and limits this service supports |
| `GET` | `/ResourceTypes`, `/ResourceTypes/{id}` | `User` and `Group` |
| `GET` | `/Schemas`, `/Schemas/{id}` | The schemas below, and one schema for each extension your IdP has sent |
| `POST` | `/Users` | Create a user (`201`) |
| `GET` | `/Users` | List and filter users |
| `POST` | `/Users/.search` | Search users with the query in the body |
| `GET` | `/Users/{id}` | Get a user |
| `PUT` | `/Users/{id}` | Replace a user |
| `PATCH` | `/Users/{id}` | Change part of a user |
| `DELETE` | `/Users/{id}` | Delete a user (`204`) |
| `POST`, `GET`, `PUT`, `PATCH`, `DELETE` | `/Groups`, `/Groups/{id}` | The same operations for groups |
| `POST` | `/Groups/.search` | Search groups |
| `POST` | `/.search` | Search users and groups together |
| `POST` | `/Bulk` | Run many operations in one request |

* `/Me` returns `501` ([LS-SCIM-1605](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1605)). The SCIM client is a connection, not a person.
* A write to a discovery endpoint returns `405`. Another method that is not in the table returns `501`.
* `changePassword` is not supported. A `password` in a request is discarded.
* `Prefer: return=minimal` on a `PATCH` returns `204` with no body. Other writes ignore it and return the resource.

## ServiceProviderConfig

| Feature | Value |
| - | - |
| `patch.supported` | `true` |
| `bulk` | `supported: true`, `maxOperations: 1000`, `maxPayloadSize: 1048576` |
| `filter` | `supported: true`, `maxResults: 1000` |
| `changePassword.supported` | `false` |
| `sort.supported` | `true` |
| `etag.supported` | `true` |
| `pagination` | `cursor: true`, `index: true`, `defaultPaginationMethod: "index"`, `defaultPageSize: 100`, `maxPageSize: 1000`, `cursorTimeout: 600` |
| `authenticationSchemes` | The methods enabled for the connection |

## Schemas

| Schema | URN |
| - | - |
| User | `urn:ietf:params:scim:schemas:core:2.0:User` |
| Group | `urn:ietf:params:scim:schemas:core:2.0:Group` |
| Enterprise user | `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User` |
| Living Security user | `urn:ietf:params:scim:schemas:extension:livingsecurity:2.0:User` |

* **User:** `userName` is required and unique in your organization, without regard to case. `externalId` is case-sensitive and need not be unique: two users can have the same one. `password` is write-only. `groups` is read-only. Every core attribute is stored and returned.
* **Enterprise user:** `employeeNumber`, `costCenter`, `organization`, `division`, `department` and `manager` (`value` is the manager's SCIM `id`).
* **Living Security user:** `startDate` (`YYYY-MM-DD`), `location`, and `employmentType`. Suggested `employmentType` values are `full-time`, `part-time`, `contractor`, `intern`, `temporary` and `vendor`. Any other text is accepted.
* **Group:** `displayName` is required and need not be unique. `externalId` need not be unique. `members` hold user or group `id` values.
* **Other extensions:** Living Security stores and returns any other extension your IdP sends, and adds it to `/Schemas`.

Every attribute, with its type, mutability, case rules and what it updates on the person, is in the [SCIM attribute reference](https://docs.livingsecurity.com/features/settings/scim/attributes.md).

## Filters

`GET /Users?filter=...`, `GET /Groups?filter=...` and the `.search` endpoints accept the full RFC 7644 filter language:

* Operators: `eq`, `ne`, `co`, `sw`, `ew`, `gt`, `ge`, `lt`, `le`, `pr`, with `and`, `or`, `not` and parentheses.
* Value paths, for example `emails[type eq "work" and value co "@example.com"]`.
* Extension paths, for example `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department eq "Finance"`.
* Attribute names are not case-sensitive. String comparison is not case-sensitive, except for attributes the schema marks `caseExact`, such as `id` and `externalId`.
* `co`, `sw` and `ew` work on text only. Only `eq` and `ne` compare with `null`.

How an attribute name resolves:

* A name that no schema has, such as a misspelled `userNmae`, returns `400` ([LS-SCIM-1305](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1305)).
* A path in an extension your IdP has not sent yet matches nobody. The list returns `totalResults: 0`, so your IdP creates the user.
* A name without a URN that exactly one extension has, such as `employeeNumber`, resolves to that extension. A name that two extensions have returns `400`.

Limits: 4 KiB of filter text, 10 levels of nesting and 50 comparisons. Over a limit returns `400` ([LS-SCIM-1304](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1304)).

An empty result is `200` with `totalResults: 0` and `Resources: []`, never `404`.

## Sorting

* `sortBy` takes any attribute. A multi-valued attribute sorts by its primary value, or its first value. A complex attribute sorts by its `value` sub-attribute.
* `sortOrder` is `ascending` (default) or `descending`.
* Ties sort by creation time, then `id`. Empty values sort last in ascending order.
* An unusable `sortBy` or `sortOrder` returns `400` ([LS-SCIM-1306](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1306)).

## Pagination

`totalResults` is always exact.

### Index pagination

* `startIndex` starts at 1 (the default). `count` defaults to 100. A `count` above 1,000 returns 1,000. `count=0` returns only `totalResults`.
* Index pagination is offset-based. If people change while you page, a page can repeat or skip a resource. Use a cursor for a full directory walk.

### Cursor pagination

1. Send an empty `cursor` (`?cursor=` or `"cursor": ""`) with your first request. Do not send `startIndex` with `cursor`.
2. Each response has `nextCursor` and, after the first page, `previousCursor`. Send `nextCursor` back as `cursor` to get the next page.
3. The last page has no `nextCursor`.

* A cursor is a position, not a snapshot. A walk without `sortBy` never skips or repeats a resource, even while resources change. A walk sorted by an attribute that changes during the walk can skip or repeat that resource, as RFC 9865 allows.
* A cursor works only with the same filter and sort, on the same connection. Any other cursor returns `400` with `scimType: invalidCursor` ([LS-SCIM-1303](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1303)).
* A cursor expires after 600 seconds. An expired cursor returns `400` with `scimType: expiredCursor` ([LS-SCIM-1307](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1307)). Start the walk again.
* A cursor sorted by a long value can be too long for a URL. Use `POST .../.search`, which carries the cursor in the body.

## PATCH

Send `schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]` and an `Operations` list.

* Operations: `add`, `remove` and `replace`, with or without `path`. Operation names are not case-sensitive, so `Replace` works.
* Path forms: `attribute`, `attribute.subAttribute`, a full extension URN with an attribute, and value filters such as `emails[type eq "work"].value` or `members[value eq "<id>"]`.
* **Extension attributes need the full URN** in `path`, for example `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber`. A bare `employeeNumber` returns `400` ([LS-SCIM-1401](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1401)).
* The text values `"True"` and `"False"`, in any case, are accepted for true and false.
* A filter path that matches nothing returns `400` with `scimType: noTarget`. A change to a read-only or immutable attribute returns `400` with `scimType: mutability`.
* Limits: 1,000 operations and 10,000 member values in one request ([LS-SCIM-1406](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1406)).

A successful PATCH returns `200` with the full resource and its new `ETag`.

## ETags and versions

* Every resource has `meta.version`, a weak ETag such as `W/"3"`. `GET`, list, write and Bulk responses all carry it.
* `If-Match` on `PUT`, `PATCH` and `DELETE` makes the write conditional. A mismatch returns `412` ([LS-SCIM-1203](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1203)). `If-Match: *` matches any existing resource.
* A write without `If-Match` always applies. Living Security never returns `428`.
* `If-None-Match` on `GET` returns `304` when the version has not changed.

## Bulk

`POST /Bulk` follows RFC 7644 section 3.7.

* Up to 1,000 operations and 1 MiB per request. More operations return `413` ([LS-SCIM-1114](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1114)).
* Operations: `POST`, `PUT`, `PATCH` and `DELETE` on `/Users` and `/Groups`. Each `POST` needs a `bulkId`.
* `bulkId:<id>` references to resources created in the same request are resolved, including circular group membership. An unresolved reference returns `409` ([LS-SCIM-1204](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1204)) for that operation.
* `failOnErrors` stops the request after that many failed operations.
* An operation's `version` works like `If-Match`.
* Each operation runs on its own. A Bulk request is not all-or-nothing: the response gives each operation's `status`, `location`, `version` and, on failure, an error body.

## Limits

| Limit | Value | Over the limit |
| - | - | - |
| Requests per token | 50 per second | `429` with `Retry-After` ([LS-SCIM-1601](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1601)) |
| Changes per organization | 25 per second. Bulk counts each operation. | `429` with `Retry-After` |
| Requests without a valid token | 600 per minute per client address | `429` with `Retry-After` |
| Request body | 1 MiB | `413` ([LS-SCIM-1110](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1110)) |
| Results per page | 1,000 | Clamped to 1,000 |
| PATCH operations | 1,000 per request | `400` |
| Group member values | 10,000 per request | `400` |
| Filter | 4 KiB, 10 levels, 50 comparisons | `400` |
| Request time | 15 seconds, 60 seconds for Bulk | `503` with `Retry-After` ([LS-SCIM-1606](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1606)) |

When Living Security pauses changes, writes return `503` with `Retry-After` ([LS-SCIM-1602](https://docs.livingsecurity.com/features/settings/scim/errors.md#ls-scim-1602)). Reads keep working.

## Errors

Errors use the SCIM error schema. The `detail` ends with an `LS-SCIM-nnnn` code and a link to the code. See the [SCIM error reference](https://docs.livingsecurity.com/features/settings/scim/errors.md).

## Related

* [Set up a SCIM connection](https://docs.livingsecurity.com/features/settings/scim/connection.md)
* [SCIM user lifecycle](https://docs.livingsecurity.com/features/settings/scim/user-lifecycle.md)
* [Receive SCIM events](https://docs.livingsecurity.com/features/settings/scim-events.md)


## Related topics

- [SCIM attribute reference](https://docs.livingsecurity.com/features/settings/scim/attributes.md)
- [SCIM and Google Workspace](https://docs.livingsecurity.com/features/settings/scim-google-workspace.md)
- [Set up SCIM with another SCIM 2.0 client](https://docs.livingsecurity.com/features/settings/scim-generic.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.