Provisioning

Prev Next

Introduction to SCIM 2.0

System for Cross-domain Identity Management (SCIM) is an open standard that enables the automation of user provisioning processes within identity management systems. SCIM simplifies the task of managing user identities in cloud-based applications and services.

SCIM sync ensures consistent and up-to-date user data across multiple systems, reducing administrative overhead and enhancing security by promptly revoking access upon user termination. It streamlines onboarding and offboarding processes, improving operational efficiency and compliance adherence.

Custom SCIM Extension Schemas

Custom SCIM extension schemas allow you to define additional user attributes beyond the standard SCIM core and enterprise user schemas. These custom schemas follow the SCIM v2 specification (RFC 7643) and are fully integrated into user provisioning operations including create, read, update (PUT and PATCH), and delete.

Extension schemas are configured per application (client) in the Visma Developer Portal. Once configured on an application, the schema is automatically applied to all tenants owned by that application and available across all SCIM user endpoints for those tenants.


Configuring Extension Schemas in Visma Developer Portal

Custom SCIM extension schemas are managed through the Visma Developer Portal under your application's settings.

To configure an extension schema:

  1. Navigate to your application in the Visma Developer Portal.

  2. In the left sidebar, go to Authentication Settings.

  3. Locate the SCIM Extension Schemas section.

  4. Click + Add Extension Schema to create a new schema, or Edit Extension Schema to modify an existing one.

SCIM Extension Schemas configuration in Visma Developer Portal

You can define the schema in two ways:

  • Manual input - Use the UI form to add attributes one by one, specifying each attribute's name, type, mutability, and other metadata.

  • JSON input - Paste a complete schema definition in JSON format directly, which is useful for importing schemas from other systems or for bulk configuration.

Each configured schema is identified by its URN, displays the number of attributes, and can be edited or deleted at any time.

Important: The extension schema configuration applies to all tenants owned by the application. Any change to the schema will affect SCIM provisioning across all of those tenants.


Key Concepts

Schema Identifier (URN)

Each custom extension schema is identified by a unique URN (Uniform Resource Name) following the SCIM convention. For example:

urn:ietf:params:scim:schemas:extension:customapp:2.0:User

This identifier is used to:

  • Declare the schema in the schemas array of SCIM requests and responses

  • Namespace extension attributes in request/response bodies

  • Reference attributes in PATCH operation paths

Attribute Types

Custom schema attributes support the following SCIM data types:

Type

JSON Representation

Description

string

"value"

A sequence of characters

boolean

true / false

A Boolean value

integer

123

A whole number

decimal

12.34

A real number with fractional part

dateTime

"2025-01-15T10:30:00Z"

An ISO 8601 / RFC 3339 timestamp

reference

"https://example.com/resource"

An absolute URI or absolute path

binary

"SGVsbG8="

A base64-encoded binary value

complex

{ "sub": "val" }

An object containing sub-attributes

Attribute Metadata

Each attribute in an extension schema has the following metadata properties that control its behavior:

Property

Supported Values

Description

multiValued

true / false

Whether the attribute holds an array of values

required

true / false

Whether the attribute must be present on create and replace (PUT)

mutability

readWrite, immutable, writeOnly

Controls how the attribute can be modified

returned

default, always, never, request

Controls when the attribute appears in responses

uniqueness

none

Uniqueness constraint (only none is supported)

caseExact

true / false

Whether string comparisons are case-sensitive. Note: since only uniqueness: none is supported, this property has no practical effect on server-side behavior

Mutability Rules

  • readWrite - The attribute can be set on create and modified on update.

  • immutable - The attribute can be set on create but cannot be changed after that. Attempts to modify an immutable attribute on PUT or PATCH will be rejected with a mutability error.

  • writeOnly - The attribute can be set in requests but is never returned in responses.

Note: readOnly mutability is not supported for custom extension schemas. Since these schemas are defined by the application, Visma Connect does not generate values for custom attributes - all values are provided by the provisioning client. If you need an attribute that should not be modified after creation, use immutable instead.

Returned Rules

  • default - The attribute is returned by default in all responses, unless excluded via the excludedAttributes query parameter.

  • always - The attribute is always returned, regardless of excludedAttributes.

  • never - The attribute is never returned in responses.

  • request - The attribute is only returned if it was included in the request body, or explicitly requested via the attributes query parameter.

Uniqueness

Only uniqueness: none is supported for custom extension schema attributes. The SCIM server does not enforce uniqueness constraints (server or global) on extension attribute values.

Complex Attributes and Sub-Attributes

Attributes of type complex can contain sub-attributes. Sub-attributes follow the same type system as top-level attributes, except that sub-attributes cannot themselves be of type complex (per RFC 7643 Section 2.3.8 - schemas are not recursive).

Complex attributes can be single-valued or multi-valued (arrays of objects).


Schema Discovery

Custom extension schemas are discoverable through the standard SCIM /Schemas endpoint. They appear alongside the built-in schemas (Core User, Enterprise User, and Group).

List All Schemas

GET /scim/v2/Schemas

Response (truncated for brevity):

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  "totalResults": 4,
  "itemsPerPage": 4,
  "Resources": [
    {
      "id": "urn:ietf:params:scim:schemas:core:2.0:User",
      "name": "User",
      "description": "User schema",
      "attributes": [ ... ],
      "meta": { ... }
    },
    {
      "id": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
      "name": "EnterpriseUser",
      "description": "Enterprise User",
      "attributes": [ ... ],
      "meta": { ... }
    },
    {
      "id": "urn:ietf:params:scim:schemas:core:2.0:Group",
      "name": "Group",
      "description": "Group schema",
      "attributes": [ ... ],
      "meta": { ... }
    },
    {
      "id": "urn:ietf:params:scim:schemas:extension:customapp:2.0:User",
      "name": "CustomApp",
      "description": "Custom application-specific user attributes",
      "attributes": [
        {
          "name": "employmentId",
          "type": "string",
          "multiValued": false,
          "required": true,
          "mutability": "readWrite",
          "returned": "default",
          "uniqueness": "none"
        },
        {
          "name": "department",
          "type": "complex",
          "multiValued": false,
          "required": false,
          "mutability": "readWrite",
          "returned": "default",
          "uniqueness": "none",
          "subAttributes": [
            {
              "name": "name",
              "type": "string",
              "multiValued": false,
              "required": true,
              "mutability": "readWrite",
              "returned": "default"
            },
            {
              "name": "code",
              "type": "string",
              "multiValued": false,
              "required": false,
              "mutability": "readWrite",
              "returned": "default"
            }
          ]
        }
      ],
      "meta": {
        "location": "https://connect.visma.com/scim/v2/Schemas/urn:ietf:params:scim:schemas:extension:customapp:2.0:User",
        "resourceType": "Schema"
      }
    }
  ]
}

Get a Specific Schema

GET /scim/v2/Schemas/{schemaUri}

Example:

GET /scim/v2/Schemas/urn:ietf:params:scim:schemas:extension:customapp:2.0:User

Returns the full schema definition for the specified extension schema. Returns 404 Not Found if the schema does not exist.


Using Extension Schemas in User Operations

Creating a User with Extension Data

When creating a user, include the extension schema URN in the schemas array and provide the extension attributes as a top-level property keyed by the schema URN.

POST /scim/v2/Users
{
  "schemas": [
    "urn:ietf:params:scim:schemas:core:2.0:User",
    "urn:ietf:params:scim:schemas:extension:customapp:2.0:User"
  ],
  "userName": "jane.doe@example.com",
  "name": {
    "givenName": "Jane",
    "familyName": "Doe"
  },
  "preferredLanguage": "en",
  "active": true,
  "addresses": [
    {
      "country": "NO",
      "type": "work",
      "primary": true
    }
  ],
  "urn:ietf:params:scim:schemas:extension:customapp:2.0:User": {
    "employmentId": "EMP-12345",
    "department": {
      "name": "Engineering",
      "code": "ENG-01"
    }
  }
}

Response (201 Created):

The response includes the extension data under the same schema URN key, filtered according to the returned rules of each attribute.

{
  "schemas": [
    "urn:ietf:params:scim:schemas:core:2.0:User",
    "urn:ietf:params:scim:schemas:extension:customapp:2.0:User"
  ],
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userName": "jane.doe@example.com",
  "name": {
    "givenName": "Jane",
    "familyName": "Doe",
    "formatted": "Jane Doe"
  },
  "active": true,
  "urn:ietf:params:scim:schemas:extension:customapp:2.0:User": {
    "employmentId": "EMP-12345",
    "department": {
      "name": "Engineering",
      "code": "ENG-01"
    }
  },
  "meta": {
    "resourceType": "User",
    "location": "https://connect.visma.com/scim/v2/Users/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "created": "2025-06-01T12:00:00Z",
    "lastModified": "2025-06-01T12:00:00Z"
  }
}

Reading a User with Extension Data

GET /scim/v2/Users/{userId}

Extension data is automatically included in the response when present, subject to the returned rules defined in the schema. If an extension schema has no data for the user, that schema URN is omitted from both the schemas array and the response body.

Replacing a User (PUT) with Extension Data

A PUT request replaces the entire user resource, including extension data. Include extension data in the same format as the create request.

PUT /scim/v2/Users/{userId}
{
  "schemas": [
    "urn:ietf:params:scim:schemas:core:2.0:User",
    "urn:ietf:params:scim:schemas:extension:customapp:2.0:User"
  ],
  "userName": "jane.doe@example.com",
  "name": {
    "givenName": "Jane",
    "familyName": "Doe"
  },
  "preferredLanguage": "en",
  "active": true,
  "addresses": [
    {
      "country": "NO",
      "type": "work",
      "primary": true
    }
  ],
  "urn:ietf:params:scim:schemas:extension:customapp:2.0:User": {
    "employmentId": "EMP-12345",
    "department": {
      "name": "Product",
      "code": "PRD-02"
    }
  }
}

Note: Immutable attributes cannot be changed on a PUT request. If you attempt to modify an immutable attribute's value (compared to its currently stored value), the request will be rejected with a 400 Bad Request and a mutability SCIM error type.

Updating Extension Data via PATCH

PATCH operations support granular updates to extension attributes using the SCIM PATCH protocol (RFC 7644 Section 3.5.2).

PATCH /scim/v2/Users/{userId}

Targeting Extension Attributes in PATCH Paths

Extension attributes are referenced in PATCH paths using their fully qualified URN followed by a colon and the attribute name:

urn:ietf:params:scim:schemas:extension:customapp:2.0:User:employmentId

For sub-attributes of complex attributes, use dot notation:

urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department.name

PATCH Operations

Add or Replace a Single Attribute
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "path": "urn:ietf:params:scim:schemas:extension:customapp:2.0:User:employmentId",
      "value": "EMP-67890"
    }
  ]
}
Add or Replace a Sub-Attribute of a Complex Attribute
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "path": "urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department.code",
      "value": "PRD-03"
    }
  ]
}
Add Values to a Multi-Valued Attribute

When using the add operation on a multi-valued attribute, the new values are appended to the existing array rather than replacing it.

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "add",
      "path": "urn:ietf:params:scim:schemas:extension:customapp:2.0:User:tags",
      "value": ["new-tag"]
    }
  ]
}
Remove an Attribute
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "remove",
      "path": "urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department"
    }
  ]
}
Update Multiple Extension Attributes Without a Path

You can update multiple extension attributes in a single operation by omitting the path and including the extension data in the value object:

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "value": {
        "urn:ietf:params:scim:schemas:extension:customapp:2.0:User": {
          "employmentId": "EMP-99999",
          "department": {
            "name": "Design",
            "code": "DSN-01"
          }
        }
      }
    }
  ]
}

Attribute Projection

The attributes and excludedAttributes query parameters support extension schema attributes using fully qualified names.

Request Specific Extension Attributes

To return only specific extension attributes, use the schema URN as a prefix:

GET /scim/v2/Users/{userId}?attributes=userName,urn:ietf:params:scim:schemas:extension:customapp:2.0:User:employmentId

This returns only the userName core attribute and the employmentId extension attribute.

Request All Attributes from an Extension Schema

Use the schema URN without an attribute name to request all attributes from that schema:

GET /scim/v2/Users/{userId}?attributes=userName,urn:ietf:params:scim:schemas:extension:customapp:2.0:User

Exclude Extension Attributes

GET /scim/v2/Users/{userId}?excludedAttributes=urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department

Sub-Attribute Projection

For complex extension attributes, you can project specific sub-attributes using dot notation:

GET /scim/v2/Users/{userId}?attributes=urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department.name

This returns only the name sub-attribute within the department complex attribute.


Validation

The SCIM API performs thorough validation on all extension data. Understanding the validation rules helps ensure that requests are well-formed.

Schema Declaration

  • Every extension schema URN present in the request body must be listed in the schemas array.

  • The schemas array must not include URNs for schemas that are not configured for the application.

Data Type Validation

  • Each attribute value must match the declared type in the schema definition.

  • Multi-valued attributes must be provided as JSON arrays; single-valued attributes must not be arrays.

  • Complex sub-attributes cannot themselves be of type complex.

  • dateTime values must conform to ISO 8601 format (e.g., 2025-01-15T10:30:00Z).

  • reference values must be valid absolute URIs or absolute paths.

  • binary values must be valid base64-encoded strings.

Required Attribute Validation

  • On create (POST) and replace (PUT), all attributes marked required: true must be present and non-null.

  • Required sub-attributes within complex attributes must also be present when the parent attribute is provided.

  • An empty array ([]) is treated as equivalent to null for required multi-valued attributes.

Immutability Validation

  • On replace (PUT), immutable attributes cannot be changed from their stored value.

  • On PATCH, replace and remove operations targeting immutable attributes (or their sub-attributes) are rejected.

  • Immutable attributes can only be set during the initial create (POST) request.

PATCH-Specific Validation

  • Required attributes cannot be removed via a remove operation.

  • Required sub-attributes within complex attributes cannot be removed.

  • Immutable attributes cannot be removed via a remove operation.

  • Filter expressions (e.g., attribute[filter].subAttribute) in PATCH paths targeting extension attributes are not supported.

  • Direct dot notation for sub-attributes of multi-valued complex attributes is not supported in PATCH paths. Use the no-path form or target the entire attribute instead.


Error Responses

When validation fails, the API returns a SCIM-compliant error response with a descriptive message and an appropriate SCIM error type.

Common Error Types

SCIM Error Type

HTTP Status

Description

invalidValue

400

Attribute value does not match the expected type, a required attribute is missing/null, or an unsupported schema is referenced

invalidSyntax

400

An attribute is not defined in the schema, extension data is not an object, or sub-attributes are not recognized

mutability

400

An immutable attribute was modified on PUT or PATCH

invalidFilter

400

A filter expression was used in a PATCH path for extension attributes (not supported)

invalidPath

400

Invalid path syntax, such as dot notation on a multi-valued complex attribute in PATCH

Example Error Response

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  "detail": "Attribute 'employmentId' in schema 'urn:ietf:params:scim:schemas:extension:customapp:2.0:User' has invalid type. Expected 'string'",
  "status": "400",
  "scimType": "invalidValue"
}

Webhook Notifications

When user resources are created, updated, or deleted through SCIM, webhook events are published. These webhooks are triggered for any changes made to the user via SCIM, not only when extension data is involved. The webhook payloads include the full SCIM user representation, including any extension data when present.

Webhooks are sent to all clients that are linked to the tenant where the change occurred.

You can add a webhook integration in the Visma Developer Portal to subscribe to these events.

Webhook Events

Event

Trigger

TENANT_SCIM_USERACCOUNT_ADDED

A user is created via SCIM

TENANT_SCIM_USERACCOUNT_MODIFIED

A user is updated via SCIM (PUT or PATCH)

TENANT_SCIM_USERACCOUNT_DELETED

A user is deleted via SCIM

Payload Structure

The TENANT_SCIM_USERACCOUNT_ADDED and TENANT_SCIM_USERACCOUNT_MODIFIED webhooks share the same payload structure. The payload contains the full SCIM user representation along with tenant, identity provider, and source metadata.

TENANT_SCIM_USERACCOUNT_ADDED / TENANT_SCIM_USERACCOUNT_MODIFIED

{
  "user": {
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:customapp:2.0:User"
    ],
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "userName": "jane.doe@example.com",
    "name": {
      "givenName": "Jane",
      "familyName": "Doe",
      "formatted": "Jane Doe"
    },
    "displayName": "Jane Doe",
    "preferredLanguage": "en",
    "locale": "en",
    "active": true,
    "externalId": "ext-12345",
    "emails": [
      {
        "primary": true,
        "value": "jane.doe@example.com",
        "type": "work"
      }
    ],
    "addresses": [
      {
        "primary": true,
        "country": "NO",
        "type": "work"
      }
    ],
    "meta": {
      "location": "https://connect.visma.com/scim/v2/Users/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "resourceType": "User",
      "created": "2025-06-01T12:00:00Z",
      "lastModified": "2025-06-01T12:00:00Z"
    },
    "urn:ietf:params:scim:schemas:extension:customapp:2.0:User": {
      "employmentId": "EMP-12345",
      "department": {
        "name": "Engineering",
        "code": "ENG-01"
      }
    }
  },
  "tenant": {
    "tenant_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
    "external_id": "tenant-ext-001",
    "application_id": "my-application-client-id"
  },
  "identity_provider": {
    "name": "SAML-MyIdentityProvider",
    "user_id": "ext-12345"
  },
  "source": {
    "name": "Api.Scim"
  }
}

Note: The extension schema data (e.g., urn:ietf:params:scim:schemas:extension:customapp:2.0:User) appears as a top-level property in the user object only if the user has extension data. The schemas array in the user object lists all schemas that have data present.

TENANT_SCIM_USERACCOUNT_DELETED

The delete webhook does not include a user payload, since the user has been removed.

{
  "tenant": {
    "tenant_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
    "external_id": "tenant-ext-001",
    "application_id": "my-application-client-id"
  },
  "identity_provider": {
    "name": "SAML-MyIdentityProvider"
  },
  "source": {
    "name": "Api.Scim"
  }
}

© 2026 Visma