---
title: "User provisioning: API integration guide"
slug: "user-provisioning-api-intgration-guide"
description: "Automate user provisioning and group management in DocuWare with SCIM 2.0 API, integrating with Azure Entra ID, Okta, and more."
updated: 2026-03-31T14:01:06Z
published: 2026-03-31T14:01:06Z
canonical: "knowledgecenter.docuware.com/user-provisioning-api-intgration-guide"
---

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

# User provisioning: API integration guide

The DocuWare User Provisioning v3 Service is a SCIM 2.0 compliant REST API that enables automatic user provisioning and group management from external Identity Providers (IdPs) such as Azure Entra ID, Okta, Ping Identity or On-premise Directory (with the help of the User Provisioning On-premise directory connector tool) to DocuWare systems.

## Base URL and endpoints

### Base URL Structure

DocuWare Cloud

```xml
https://{your-organization}.docuware.cloud/DocuWare/Services/UserProvisioningService/{externalIdp}/scim
```

DocuWare on-premises

```xml
http(s)://{your-server-address}/DocuWare/Services/UserProvisioningService/{externalIdp}/scim
```

Where `{externalIdp}` can be:

- `azure` - for Azure Entra ID
- `okta `- for Okta
- `ping` - for Ping Identity
- `onpremise` - for on-premise directories
- `generic-{identifier}` - for generic identity providers

### Available Endpoints

| **Resource** | **HTTP Method** | **Endpoint** | **Description** |
| --- | --- | --- | --- |
| **Users** | GET | `/{externalIdp}/scim/Users` | Get all external users with optional filtering by userName or externalId |
|  | GET | `/{externalIdp}/scim/Users?allDocuWareUsers=true` | Get all users with optional filtering by userName or externalId |
|  | GET | `/{externalIdp}/scim/Users/{id}` | Get specific user by ID |
|  | POST | `/{externalIdp}/scim/Users` | Create new user |
|  | PUT | `/{externalIdp}/scim/Users/{id}` | Replace user completely |
|  | PATCH | `/{externalIdp}/scim/Users/{id}` | Partial user update |
|  | DELETE | `/{externalIdp}/scim/Users/{id}` | Delete user |
| **Groups** | GET | `/{externalIdp}/scim/Groups` | Get all groups with optional filtering by displayName |
|  | GET | `/{externalIdp}/scim/Groups/{id}` | Get specific group by ID |
|  | POST | `/{externalIdp}/scim/Groups` | Create new group |
|  | PUT | `/{externalIdp}/scim/Groups/{id}` | Replace group completely |
|  | PATCH | `/{externalIdp}/scim/Groups/{id}` | Partial group update |
|  | DELETE | `/{externalIdp}/scim/Groups/{id}` | Delete group |
| **Schemas** | GET | `/{externalIdp}/scim/Schemas` | Get SCIM schemas |
| **Resource Types** | GET | `/{externalIdp}/scim/ResourceTypes` | Get supported resource types |
| **Health Check** | GET | `/AvailabilityCheck` | Service availability check |

## Authentication

### JWT Bearer Authentication

All endpoints (except health check) require JWT Bearer token authentication:

```json
Authorization: Bearer {jwt-token}
```

### Content Type

All requests must use the SCIM content type:

```json
Content-Type: application/scim+json
```

## User Management

### User Schema (Core2EnterpriseUser)

### Get Users (GET)

The GET Users endpoint supports multiple variants for retrieving user data with optional filtering and pagination. By default, it returns only users with external IDs (users from external identity providers).

#### 1. Get All External Users (Default)

```json
GET /{externalIdp}/scim/Users
Authorization: Bearer {token}
```

Returns all users that have an externalId (users from external identity providers).

**Response:**

```json
{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],

  "totalResults": 2,

  "itemsPerPage": 2,

  "startIndex": 1,

  "resources": [

    {

      "userName": "john.doe",

      "active": true,

      "emails": [

        {

          "value": "john.doe@example.com",

          "primary": true

        }

      ],

      "name": {

        "givenName": "John",

        "familyName": "Doe"

      },

      "id": "external-user-id-123",

      "meta": {

        "resourceType": "User"

      },

      "schemas": [

        "urn:ietf:params:scim:schemas:core:2.0:User",

        "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"

      ],

    },

    {

      "userName": "jane.smith",

      "active": true,

      "emails": [

        {

          "value": "jane.smith@example.com",

          "primary": true

        }

      ],

      "name": {

        "givenName": "Jane",

        "familyName": "Smith"

      },

      "id": "external-user-id-456",

      "meta": {

        "resourceType": "User"

      },

      "schemas": [

        "urn:ietf:params:scim:schemas:core:2.0:User",

        "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"

      ]

    }

  ]

}
```

#### 2. Get All DocuWare Users

```json
GET /{externalIdp}/scim/Users?allDocuWareUsers=true
Authorization: Bearer {token}
```

Returns all users in the DocuWare system, including both external users and internal DocuWare users.

> [!NOTE]
> Note: internal users have no id
> 
> Internal users do not have `id` in the response´, because they are not external and don't have an `externalId` attribute set, which is the one returned as `id`.

**Response**

```json
{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],

  "totalResults": 2,

  "itemsPerPage": 2,

  "startIndex": 1,

  "resources": [

    {

      "userName": "john.doe",

      "active": true,

      "emails": [

        {

          "value": "john.doe@example.com",

          "primary": true

        }

      ],

      "name": {

        "givenName": "John",

        "familyName": "Doe"

      },

      "id": "external-user-id-123",

      "meta": {

        "resourceType": "User"

      },

      "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User",

        "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],

    },

    {

      "userName": "jane.smith",

      "active": true,

      "emails": [

        {

          "value": "jane.smith@example.com",

          "primary": true

        }

      ],

      "name": {

        "givenName": "Jane",

        "familyName": "Smith"

      },

      "meta": {

        "resourceType": "User"

      },

      "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User",

        "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"]

    }

  ]

}
```

#### 3. Get Specific User by ID

```json
GET /{externalIdp}/scim/Users/{externalId}

Authorization: Bearer {token}
```

Returns a specific user by their external ID.

**Response:**

```json
{

  "userName": "john.doe",

  "active": true,

  "emails": [

    {

      "value": "john.doe@example.com",

      "primary": true

    }

  ],

  "name": {

    "givenName": "John",

    "familyName": "Doe"

  },

  "id": "external-user-id-123",

  "meta": {

    "resourceType": "User"

  },

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User",

    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],

}
```

#### 4. Query users with filtering

**Filter by Username (in External Users):**

```json
GET /{externalIdp}/scim/Users?filter=userName eq "john.doe"

Authorization: Bearer {token}
```

**Filter by username in All DocuWare Users:**

```json
GET /{externalIdp}/scim/Users?allDocuWareUsers=true&filter=userName eq "john.doe"

Authorization: Bearer {token}
```

**Filter by External ID:**

```json
GET /{externalIdp}/scim/Users?filter=externalId eq "external-user-id-123"

Authorization: Bearer {token}
```

**Get Users with pagination:**

```json
GET /{externalIdp}/scim/Users?startIndex=2&count=5

Authorization: Bearer {token}
```

```json
GET /{externalIdp}/scim/Users?allDocuWareUsers=true&startIndex=2&count=5

Authorization: Bearer {token}
```

#### Supported query parameters

Pagination:

- startIndex - 1-based index of the first result (default: 1, minimum: 1)
- count - Number of results per page (default: all results if not specified, minimum: 0)

Filtering:

- filter - SCIM filter expression (supports only userName eq "value" & externalId eq "value") (case insensitive)

#### Response Format

All GET /Users requests return a SCIM ListResponse with the following structure:

**Properties:**

- schemas - Array containing "urn:ietf:params:scim:api:messages:2.0:ListResponse"
- totalResults - Total number of matching users
- itemsPerPage - Number of users returned in current response
- startIndex - Starting index of current page (1-based)
- Resources - Array of user objects

#### Error Responses

400 Bad Request - Invalid Filter:

```json
{

  "ScimType": "invalidFilter",

  "Detail": "Unsupported filter attribute: FirstName",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

```json
{

  "ScimType": "invalidFilter",

  "Detail": "Unsupported comparison operator: 'ne'",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

All GET `/Users/{externalId}` requests return a User object with following structure:

**User Object Properties:**

- `id` - User's external ID
- `userName` - User's login name (without domain if email for non-generic Idps)
- `active` - User's active status (boolean)
- `emails` - Array of email objects with value, primary properties
- `name` - Object with givenName and familyName properties
- `meta` - Metadata object with resourceType: "User"
- `schemas` - Array of SCIM schema identifiers

#### Error Responses

**404 Not Found - User Not Found:**

```json
{

  "Detail": "User with External ID 'external-user-id-404' was not found.",

  "Status": 404,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

#### Examples

Get first 5 external users:

```json
GET /{externalIdp}/scim/Users?startIndex=1&count=5
```

Get external users starting from a position:

```json
GET /{externalIdp}/scim/Users?startIndex=10&count=20
```

Find user by username:

```json
GET /{externalIdp}/scim/Users?filter=userName eq "john.doe"
```

Find user by username in all DocuWare users:

```json
GET /{externalIdp}/scim/Users?allDocuWareUsers=true&filter=userName eq "jane.smith"
```

Find user by externalId:

```json
GET /{externalIdp}/scim/Users?filter=externalId eq "external-user-id-123"
```

Get all DocuWare users with pagination:

```json
GET /{externalIdp}/scim/Users?allDocuWareUsers=true&startIndex=1&count=50
```

### Create user (POST)

#### How user creation works

The system implements an intelligent user creation/update logic that follows these steps:

1. User Lookup by External ID: First attempts to find an existing user by the provided externalId, if one is found - that is a complete match and the existing user is being updated with the request attributes.
2. Fallback to Username Lookup: If no user is found by external ID, searches by username extracted from the `userName` field, if one is found and the incomming email matches the existing user email - that is a complete match and the existing user is being updated with the attributes from the request. Otherwise when emails do not match - new user fails to be created, because a user with the provided `userName` already exists. (resulting in a 409 Conflict)

User Creation versus Update Logic:

- **New User**: If no existing user is found by `externalID` or `userName`, creates a new user
- **User Update**: If an existing user is found and matched either by `externalId` or `userName` + email, updates the user's information
- **Email Validation**: When finding by `userName`, validates that the existing user's email matches the provided email (case-insensitive). If emails don't match, throws an exception to prevent conflicts

> [!NOTE]
> Notes on email address resolution service
> 
> The service determines the user's email address using the following priority order:
> 
> 1. **Primary Email**: Uses the email marked as primary: true in the emails array.
> 2. **First Valid Email**: If no primary email exists, selects the first valid email from the emails array.
> 3. **Validation**: If none of the above are valid email addresses, the request fails with a 400 Bad Request.

#### Request

```json
POST /{externalIdp}/scim/Users

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],

  "userName": "john.doe@example.com",

  "externalId": "external-user-id-123",

  "active": true,

  "name": {

    "givenName": "John",

    "familyName": "Doe"

  },

  "emails": [

    {

      "value": "john.doe@example.com",

      "primary": true

    }

  ]

}
```

#### Required and Optional Fields

Required fields:

- `schemas` - SCIM schema identifiers (must include both Core and Enterprise User schemas)
- `userName `- User's login name (must be unique)
- `externalId `- External identity provider user ID (must be unique)
- `active` - User active status
- `emails` - Array of email addresses

Optional Fields:

- `name` - User's display name object
  - `name.givenName` - First name
  - `name.familyName` - Last name

Field Validation Rules:

- **UserName**: Required, case-sensitive, must not be empty or whitespace
- **ExternalId**: Required, case-sensitive, must not be empty or whitespace
- **Emails**: At least one valid email must be resolvable (in case of multiple **Email Address Resolution** rules are respected)
- **Active**: Boolean value
- **Name fields**: Optional strings for display purposes

#### Response

**Success (200 OK):**

```json
{

  "userName": "john.doe",

  "active": true,

  "emails": [

    {

      "value": "john.doe@example.com",

      "primary": true

    }

  ],

  "name": {

    "givenName": "John",

    "familyName": "Doe"

  },

  "id": "external-user-id-123",

  "meta": {

    "resourceType": "User"

  },

  "schemas": [

      "urn:ietf:params:scim:schemas:core:2.0:User",

      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"

  ]

}
```

#### Error Responses

400 Bad Request - Missing Required Fields:

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: UserName: is required",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

409 Conflict - User already exists:

```json
{

  "ScimType": "uniqueness",

  "Detail": "User with username 'john.doe' already exists with different email address!",

  "Status": 409,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

### Update user (PUT) - complete user replacement

The PUT operation performs a complete replacement of a user resource. Unlike PATCH, which updates only specified fields, PUT replaces the entire user object with the provided data.

#### Basic PUT Request

```json
PUT /{externalIdp}/scim/Users/{externalId}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "userName": "john.doe",

  "externalId": "external-user-id-123",

  "active": true,

  "emails": [

    {

      "value": "john.doe@example.com",

      "primary": true

    }

  ],

  "name": {

    "givenName": "John",

    "familyName": "Doe"

  },

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"]

}
```

#### **Parameters**

- `{externalIdp} `- External identity provider identifier (azure, okta, ping, onpremise, etc.)
- `{externalId} `- The external ID of the user to update

#### Required fields for PUT

**All fields that are mandatory for user creation must be provided:**

- `userName `- User's login name
- `externalId` - External identity provider user ID
- `active` - User active status (boolean, defaults to false if not provided)
- `emails` - Array of email addresses (check **Email Address Resolution**)
- `schemas` - SCIM schema identifiers (must include both Core and Enterprise User schemas)

#### Optional fields (old values are persisted if new ones are not provided)

- name - User's display name object
  - name.givenName - First name
  - name.familyName - Last name

#### Complete PUT Example

```json
PUT /azure/scim/Users/external-user-id-123

Content-Type: application/scim+json

Authorization: Bearer {jwt-token}

{

  "userName": "john.smith",

  "externalId": "external-user-id-123",

  "active": false,

  "name": {

    "givenName": "John",

    "familyName": "Smith"

  },

  "emails": [

    {

      "value": "john.smith@example.com",

      "primary": true

    }

  ],

  "schemas": [

    "urn:ietf:params:scim:schemas:core:2.0:User",

    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"

  ]

}
```

#### Response

Success (200 OK):

```json
{

  "userName": "john.smith",

  "active": false,

  "emails": [

    {

      "value": "john.smith@example.com",

      "primary": true

    }

  ],

  "name": {

    "givenName": "John",

    "familyName": "Smith"

  },

  "id": "external-user-id-123",

  "meta": {

    "resourceType": "User"

  },

  "schemas": [

    "urn:ietf:params:scim:schemas:core:2.0:User",

    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"

  ]

}
```

#### Error Responses

400 Bad Request - Missing Required Fields

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: UserName: is required",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

404 Not Found - User Not Found:

```json
{

  "Detail": "User with External ID 'external-user-id-404' was not found.",

  "Status": 404,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

409 Conflict - Duplicate Username:

```json
{

    "ScimType": "uniqueness",

    "Detail": "User with username 'john.doe' already exists!",

    "Status": 409,

    "Schemas": [

        "urn:ietf:params:scim:api:messages:2.0:Error"

    ]

}
```

409 Conflict - Duplicate ExternalId:

```json
{

  "ScimType": "uniqueness",

  "Detail": "User with External ID 'external-user-id-409' already exists!",

  "Status": 409,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

409 Conflict - Locked Resource:

```json
{

  "ScimType": "mutability",

  "Detail": "The resource with ID 'external-user-id-409' is immutable.",

  "Status": 409,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

#### Validation Rules for PUT

All validation rules from POST operations apply to PUT operations:

- **UserName**: Required, case-sensitive, must not be empty or whitespace
- **ExternalId**: Required, case-sensitive, must not be empty or whitespace
- **Active**: boolean value (defaults to `false` if not provided)
- **Emails**: At least one valid email must be resolvable (in case of multiple **Email Address Resolution** rules are respected)
- **Name Fields**: Optional but recommended for user experience
- **Schemas**: Must include both Core and Enterprise User schemas

### Patch User (PATCH) operations guide

The PATCH operation allows partial updates to user attributes using SCIM 2.0 patch operations. The service supports `replace` and `add` operations for user updates.

#### **Basic PATCH structure:**

```json
PATCH /{externalIdp}/scim/Users/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "replace",

      "path": "attribute_path",

      "value": "new_value"

    },

    {

      "op": "add",

      "path": "attribute_path",

      "value": "new_value"

    }

  ]

}
```

#### **Supported Operations**

- `replace` - Update an existing attribute value
- `add `- Update an empty/existing attribute value
- `remove` - Not supported for user operations

#### **Supported attribute paths**

User Activity Status:

```json
{
  "op": "replace",
  "path": "active",
  "value": "false"
}
```

Username update:

```json
{
  "op": "replace",
  "path": "userName", 
  "value": "new.username"
}
```

Name Fields:

```json
{
  "op": "replace",
  "path": "name.givenName",
  "value": "NewFirstName"
}
```

```json
{

  "op": "replace",

  "path": "name.familyName", 

  "value": "NewLastName"

}
```

Email address:

```json
{
  "op": "replace",
  "path": "emails",
  "value": "new.email@example.com"
}
```

```json
{
  "op": "replace",
  "path": "emails[primary eq true].value",
  "value": "new.email@example.com"
}
```

**Notes:**

- Both syntaxes for emails path are valid
- Email address must be in valid email format

External ID

```json
{
  "op": "replace",
  "path": "externalId",
  "value": "new-external-id-456"
}
```

Multiple Operations Example:

```json
PATCH /{externalIdp}/scim/Users/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "replace",

      "path": "active",

      "value": "false"

    },

    {

      "op": "replace", 

      "path": "name.givenName",

      "value": "Jonathan"

    },

    {

      "op": "replace",

      "path": "name.familyName",

      "value": "Smith"

    },

    {

      "op": "replace",

      "path": "emails",

      "value": "jonathan.smith@example.com"

    }

  ]

}
```

> [!NOTE]
> Important notes:
> 
> - All operations are processed in sequence
> - The `remove` operation is not supported and will return an error
> - Email validation is performed for email-related fields
> - The `active `field requires boolean string values ("true" or "false")
> - Invalid attribute paths will result in a 400 Bad Request error
> - If the `externalId` or `userName` is already taken by another user, that will result in a conflict error

Error Handling:

- **400 Bad Request**: Invalid operation type, unsupported path, or validation failure
- **404 Not Found**: User with specified ID not found
- **409 Conflict**: Update would create a conflict (e.g., duplicate username, externalId)

#### Supported user attributes for PATCH operations

- `userName` - User's login name
- `externalId `- External identity provider user ID
- `name.givenName` - First name
- `name.familyName` - Last name
- `active` - User active status (true/false)
- `emails/emails[].value `- Email address

### Delete User (DELETE)

The DELETE operation soft deletes a user from the DocuWare system. This operation deactivates the user.

#### Basic DELETE Request

```json
DELETE /{externalIdp}/scim/Users/{externalId}

Authorization: Bearer {token}
```

Parameters:

- `{externalIdp} `- External identity provider identifier (azure, okta, ping, etc.)
- `{externalId} `- The external ID of the user to delete

#### Request Example

```json
DELETE /azure/scim/Users/external-user-id-123

Authorization: Bearer {jwt-token}
```

#### Response

Success (204 No Content):

```json
HTTP/1.1 204 No Content
Content-Type: application/scim+json
```

The DELETE operation returns HTTP 204 (No Content) with an empty response body when successful.

#### Error Responses

404 Not Found - User Not Found:

```json
{

  "Detail": "User with External ID 'ExternalUser112' was not found.",

  "Status": 404,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

409 Conflict - User is currently locked and cannot be deleted:

```json
{

  "ScimType": "mutability",

  "Detail": "The resource 'ExternalUser11' with ID 'ExternalUser11' is immutable.",

  "Status": 409,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

Alternative to deletion: Instead of deleting a user, alternative is deactivating them using a PATCH or PUT operation:

```json
PATCH /{externalIdp}/scim/Users/{externalId}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "replace",

      "path": "active",

      "value": "false"

    }

  ]

}
```

## Group Management

### Group Schema (Core2Group)

### How Group Creation Works

The system implements an intelligent group creation/update logic that follows these steps:

1. Group Lookup by DisplayName: First attempts to find an existing group by the provided `displayName`, if one is found it's treated as Group Update, otherwise - Group Creation
2. Group creation versus update logic:
  - New Group: If no existing group is found by `displayName`, creates a new group with the provided members
  - Group Update: If an existing group is found, updates the group's information and adds new members to the existing membership (does not replace existing members)
  - Member Addition: New members are added to existing groups without removing current members
  - Duplicate Prevention: The system prevents adding duplicate members to groups

> [!NOTE]
> Important Group Creation Notes:
> 
> - Display Name Uniqueness: Groups are identified by their `displayName`
> - Member Resolution: All member references (`value` field) must be valid `externalId` values of existing users
> - Incremental Membership: POST operations on existing groups add members incrementally rather than replacing the entire membership
> - Member Validation: The system only adds members that exist. If member with provided `value` (externalId) does not exist - it's being skipped with no error returned.
> - External Identity Provider Scope: You can only manage the part of the group that consists of users from the current `externalIdp`. Users from other external identity providers or internal DocuWare users remain unaffected by these operations.
> - Response: The response includes only group members who are external users provisioned by the specified `externalIdp` (such as azure, okta, ping, onpremise or generic). Internal users or users created by other external identity providers are excluded from the response.

Member reference format:

- Members are referenced by their` externalId` (not internal DocuWare user ID)
- Each member object must contain a `value `field with the user's external ID
- Optional `display` field (users `userName`) can be provided but is not required for membership assignment

### Create Group (POST)

```json

POST /{externalIdp}/scim/Groups

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "displayName": "Engineering Team",

  "members": [

    {

      "value": "external-user-id-123"

    },

    {

      "value": "external-user-id-456"

    }

  ]

}
```

#### Response

```json

{

  "displayName": "Engineering Team",

  "members": [

    {

      "value": "external-user-id-123",

      "display": "john.doe"

    },

    {

      "value": "external-user-id-456",

      "display": "jane.smith"

    }

  ],

  "id": "12345678-1234-1234-1234-123456789012",

  "meta": {

    "resourceType": "Group"

  },

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"]

}
```

**Empty Group Creation:**

```json
POST /{externalIdp}/scim/Groups

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "displayName": "Future Project Team",

  "members": []

}
```

**Mandatory Fields:**

- `schemas` - SCIM schema identifiers (must include `"urn:ietf:params:scim:schemas:core:2.0:Group"`)
- `displayName` - Group's display name (used for identification)
- `members` - Array of member objects (can be empty for group creation)
  - `members[].value `- User's external ID (required if members are specified)

#### Error Responses

**400 Bad Request - Missing Required Fields:**

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: DisplayName: is required",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: Members: The Members field is required.",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: Members[0].Value: Member Value is required.",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

### Get groups (GET)

The GET Groups endpoint supports multiple variants for retrieving group data with optional filtering and pagination. Groups include members that are external users from the specified external identity provider.

#### 1. Get all groups (default)

```json
GET /{externalIdp}/scim/Groups
Authorization: Bearer {token}
```

Returns all groups that exist in DocuWare, without returning the members, they can be queried with the GET request: /Groups/{groupId}

Response:

```json
{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],

  "totalResults": 2,

  "itemsPerPage": 2,

  "startIndex": 1,

  "resources": [

    {

      "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

      "id": "group-id-123",

      "displayName": "Engineering Team",

      "meta": {

        "resourceType": "Group"

      }

    },

    {

      "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

      "id": "group-id-456",

      "displayName": "Marketing Team",

      "meta": {

        "resourceType": "Group",

      }

    }

  ]

}
```

#### 2. Get Specific Group by ID

```json
GET /{externalIdp}/scim/Groups/{groupId}

Authorization: Bearer {token}
```

Retrieves details for a specific group using its group ID. The `members` attribute includes only external users provisioned by the specified identity provider.

**Response:**

```json
{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "displayName": "Engineering Team",

  "members": [

    {

      "value": "external-user-id-123",

      "display": "john.doe",

    },

    {

      "value": "external-user-id-456",

      "display": "jane.smith",

    }

  ],

  "id": "group-external-id-123",

  "meta": {

    "resourceType": "Group"

  }

}
```

#### 3. Query Groups with Filtering

Filter by Display Name:

```json
GET /{externalIdp}/scim/Groups?filter=displayName eq "Engineering Team"

Authorization: Bearer {token}
```

Get Groups with Pagination:

```json
GET /{externalIdp}/scim/Groups?startIndex=1&count=10

Authorization: Bearer {token}
```

```json
GET /{externalIdp}/scim/Groups?startIndex=2&count=5

Authorization: Bearer {token}
```

#### Supported Query Parameters

Filtering:

- `filter `- SCIM filter expression (supports only displayName eq "value") (case-insensitive, exact match)

**Pagination:**

- `startIndex `- 1-based index of the first result (default: 1, minimum: 1)
- `count `- Number of results per page (default: all results if not specified, minimum: 0)

#### Response Format

All GET /`Groups` requests return a SCIM ListResponse with the following structure:

**ListResponse Properties:**

- `schemas` - Array containing `"urn:ietf:params:scim:api:messages:2.0:ListResponse"`
- `totalResults `- Total number of matching groups
- `itemsPerPag`e - Number of groups returned in current response
- `startIndex` - Starting index of current page (1-based)
- `resources `- Array of group objects (members attribute available only when fetched by group ID)

**Group Object Properties:**

- `id` - Group's external ID
- `displayName` - Group's display name
- `members` - Array of member objects (only external users from the specified `externalIdp`)
  - `value `- Member's external user ID
  - `display` - Member's username
- `meta `- objects resource type
- `schemas` - Array containing SCIM schema identifiers

#### 

> [!NOTE]
> Notes about group responses
> 
> **Member Filtering:**
> 
> - Only members who are external users managed by the specified {`externalIdp`} are included in responses
> - Internal DocuWare users and users from other external identity providers are excluded
> - Empty groups (no qualifying members) may still appear in results if they exist
> 
> **Group Identification:**
> 
> - Groups are identified by their `ID `for GET operations
> - The displayName is used for filtering and group lookup during creation/updates

#### Error Responses

400 Bad Request - Invalid Filter:

Filtering by wrong attribute:

```json
{

  "ScimType": "invalidFilter",

  "Detail": "Unsupported filter attribute: id",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

Filtering with invalid expression (only valid is - filter=displayName eq "groupName"):

```json
{

  "ScimType": "invalidFilter",

  "Detail": "Invalid filter expression: 'displasyname asd \"engineering team\"'",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

Filtering with unsupported comparison operator:

```json
{

  "ScimType": "invalidFilter",

  "Detail": "Unsupported comparison operator: 'ne'",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

404 Not Found - Group Not Found:

```json
{

  "Detail": "Group with identifier 'group-id-404' was not found.",

  "Status": 404,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

### Update Group Membership (PATCH)

The PATCH operation allows partial updates to group attributes using SCIM 2.0 patch operations. The service supports add, remove and replace(only for group displayName) operations for group management.

#### Basic PATCH Structure

```json
PATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "operation_type",

      "path": "attribute_path",

      "value": "new_value_or_array"

    }

  ]

}
```

#### Supported Operations

Add Members (`add`): adds new members to the group without removing existing members.

```json
vPATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "add",

      "path": "members",

      "value": [

        {

          "value": "external-user-id-789"

        },

        {

          "value": "external-user-id-101"

        }

      ]

    }

  ]

}
```

Remove specific members (`remove`): removes specified members from the group.

```json
PATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "remove",

      "path": "members",

      "value": [

        {

          "value": "external-user-id-123"

        },

        {

          "value": "external-user-id-456"

        }

      ]

    }

  ]

}
```

Remove All Members (`remove`): removes all members that are users created by the provided externalIdp from the group (empties the group).

```json
PATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "remove",

      "path": "members"

    }

  ]

}
```

When no `value `is provided with remove operation, all external members (from the provided externalIdp) are removed.

1. **Replace Group Display Name (**replace**)** Updates the group's display name.

```json
PATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "replace",

      "path": "displayName",

      "value": "Updated Team Name"

    }

  ]

}
```

#### Supported Attribute Paths

| **Path** | **Operations** | **Description** | **Value Format** |
| --- | --- | --- | --- |
| `displayName` | `replace, add` | Group display name | String |
| `members` | `add, remove` | Group membership | Array of member objects |

#### Multiple Operations in Single Request

You can combine multiple operations in a single PATCH request:

```json
PATCH /{externalIdp}/scim/Groups/{id}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],

  "Operations": [

    {

      "op": "replace",

      "path": "displayName",

      "value": "DevOps Engineering Team"

    },

    {

      "op": "add",

      "path": "members",

      "value": [

        {

          "value": "external-user-id-new1"

        }

      ]

    },

    {

      "op": "remove",

      "path": "members",

      "value": [

        {

          "value": "external-user-id-old1"

        }

      ]

    }

  ]

}
```

#### Member Object Format

When specifying members in operations, use this format:

**Required Fields:**

- `value` - The external ID of the user to add/remove

**Example Member Object:**

```json
{
  "value": "external-user-id-123"
}
```

#### Operation Behavior Details

**Add Operation:**

- Adds specified members to the group
- Ignores members that are already in the group (no duplicates)
- Non-existent user external IDs are silently ignored
- Does not affect existing members

**Remove Operation:**

- With `value`: Removes only the specified members (if they are users created from provided externalIdp)
- Without `value`: Removes all members (users created from provided externalIdp) from the group
- Ignores external IDs that are not current members
- Does not affect non-specified members

**Replace Operation:**

- For `displayName`: Updates the group name

#### Responses

- Successful PATCH Response (204 No Content)
- 400 Bad Request - Invalid Operation
- 400 Bad Request - Invalid Path
- 400 Bad Request - Invalid Member Format
- 404 Not Found - Group Not Found
- 409 Conflict - Group Name Already Exists

#### Important PATCH Operation Notes

**Operation Processing:**

- Operations are processed sequentially in the order they appear

**Member Validation:**

- User external IDs must reference existing users
- Invalid external IDs are silently ignored (no error thrown)
- Only external users from the same identity provider (`externalIdp`) are managed

**Group State:**

- The response includes only external users from the specified `{externalIdp}`
- Internal DocuWare users and users from other identity providers are excluded from responses
- Empty groups remain valid and are included in responses

### Update Group (PUT) - Complete Group Replacement

The PUT operation performs a complete replacement of the group part provided by the externalIdp. Unlike PATCH, which updates only specified fields, PUT replaces the entire group object with the provided data.

#### Basic PUT Request

```json
PUT /{externalIdp}/scim/Groups/{groupId}

Content-Type: application/scim+json

Authorization: Bearer {token}

{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "displayName": "Updated Engineering Team",

  "members": [

    {

      "value": "external-user-id-123"

    },

    {

      "value": "external-user-id-456"

    }

  ]

}
```

#### Parameters

- `{externalIdp} `- External identity provider identifier (azure, okta, ping, etc.)
- `{groupId} `- The ID of the group to update

#### Required Fields for PUT

All fields that are mandatory for group creation must be provided:

- `schemas` - SCIM schema identifiers (must include `"urn:ietf:params:scim:schemas:core:2.0:Group"`)
- `displayName` - Group's display name
- `members` - Array of member objects (can be empty)

#### Complete PUT Example

```json
PUT /azure/scim/Groups/group-id-123

Content-Type: application/scim+json

Authorization: Bearer {jwt-token}

{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "displayName": "DevOps Engineering Team",

  "members": [

    {

      "value": "external-user-id-789"

    },

    {

      "value": "external-user-id-101"

    }

  ]

}
```

#### Response

Success (200 OK):

```json
{

  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],

  "id": "group-id-123",

  "displayName": "DevOps Engineering Team",

  "members": [

    {

      "value": "external-user-id-789",

      "display": "john.doe",

    },

    {

      "value": "external-user-id-101",

      "display": "jane.smith",

    }

  ],

  "meta": {

    "resourceType": "Group"

  }

}
```

> [!NOTE]
> Important PUT Behavior Notes
> 
> 1. **Complete Member Replacement**: PUT replaces the entire member list managed by current `externalIdp`. Any member not included in the request will be removed from the group.
> 2. **Display Name Update**: The group's display name can be changed using PUT operations.
> 3. **Member Validation**: All specified member external IDs must reference existing users. Invalid external IDs will be skipped silently.
> 4. **External Identity Provider Scope**: Only members who are external users from the specified `{externalIdp}` are managed by this operation. Internal DocuWare users and users from other identity providers remain unaffected.
> 5. **Group Identification**: The group is identified by the` {groupId}` parameter in the URL.

#### Error Responses

400 Bad Request - Missing Required Fields:

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed: DisplayName: is required",

  "Status": 400,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

404 Not Found - Group Not Found:

```json
{

  "Detail": "Group with identifier 'group-id-404' was not found.",

  "Status": 404,

  "Schemas": [

      "urn:ietf:params:scim:api:messages:2.0:Error"

  ]

}
```

#### Validation Rules for PUT

All validation rules from POST operations apply to PUT operations:

- **DisplayName**: Required, case-sensitive, must not be empty or whitespace
- **Members**: Optional array, each member must have a valid value field with existing user's external ID
- **Member External IDs**: Must reference existing users from the same external identity provider
- **Schemas**: Must include the Core Group schema

### Delete Group (DELETE) - Not Supported

The DELETE operation for groups is **not supported** by the DocuWare User Provisioning v3 Service. Attempting to delete a group will result in an error response.

## HTTP Status Codes

| **Status Code** | **Description** | **When Used** |
| --- | --- | --- |
| 200 OK | Success | GET, PATCH operations |
| 201 Created | Resource created | POST operations |
| 204 No Content | Success, no content | DELETE, some PATCH operations |
| 400 Bad Request | Invalid request | Validation errors |
| 401 Unauthorized | Authentication required | Missing/invalid token |
| 403 Forbidden | Access denied | Insufficient permissions |
| 404 Not Found | Resource not found | Invalid resource ID |
| 409 Conflict | Resource conflict | Duplicate username/email |
| 500 Internal Server Error | Server error | Service issues |
| 501 Not Implemented | Not supported | Not supported by product |

## Error Response Format

```json
{

  "ScimType": "invalidValue",

  "Detail": "Validation failed.",

  "Status": 400,

  "Schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"]

}
```

## Configuration Requirements

### Identity Provider Setup

1. Configure your IdP to point to the appropriate tenant URL
2. Set up OAuth 2.0/OIDC authentication with JWT tokens
3. Configure the correct scopes: `docuware.userProvisioning`
4. Make sure the user performing API operations has sufficient permissions.

### Supported Identity Providers

- **Azure Entra ID (Azure AD)**: Use `azure` as externalIdp
- **Okta**: Use `okta` as externalIdp
- **Ping Identity**: Use `ping` as externalIdp
- **On-Premise**: Use `onpremise` as externalIdp
- **Generic Idp**

## Schema Information

### Get Available Schemas

```json
GET /{externalIdp}/scim/Schemas
Authorization: Bearer {token}
```

### Get Resource Types

```json
GET /{externalIdp}/scim/ResourceTypes  
Authorization: Bearer {token}
```

## Health Check

### Service Availability

```json
GET /AvailabilityCheck
```

This endpoint requires no authentication and returns 200 OK if the service is running.

## Example Integration Workflows

### Complete User Provisioning Workflow

1. **Create User**: POST to `/Users` with user details
2. **Verify Creation**: GET `/Users/{id}` to confirm
3. **Update User**: PATCH `/Users/{id}` for changes
4. **Add to Groups**: PATCH `/Groups/{groupId}` to add user
5. **Deactivate**: PATCH `/Users/{i`d} with `active: false`

### Group Management Workflow

1. **Create Group**: POST to `/Groups` with group details
2. **Add Members**: PATCH `/Groups/{id}` with add operations
3. **Update Name**: PATCH `/Groups/{id}` with displayName change
4. **Remove Members**: PATCH /`Groups/{id}` with remove operations

This API provides a robust, standards-compliant interface for managing users and groups in DocuWare through external identity providers while maintaining security and performance best practices.

## Supported versions: DocuWare Cloud + 7.14 + 7.13
