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:
Navigate to your application in the Visma Developer Portal.
In the left sidebar, go to Authentication Settings.
Locate the SCIM Extension Schemas section.
Click + Add Extension Schema to create a new schema, or Edit Extension Schema to modify an existing one.
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:UserThis identifier is used to:
Declare the schema in the
schemasarray of SCIM requests and responsesNamespace 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 |
|---|---|---|
|
| A sequence of characters |
|
| A Boolean value |
|
| A whole number |
|
| A real number with fractional part |
|
| An ISO 8601 / RFC 3339 timestamp |
|
| An absolute URI or absolute path |
|
| A base64-encoded binary value |
|
| 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 |
|---|---|---|
|
| Whether the attribute holds an array of values |
|
| Whether the attribute must be present on create and replace (PUT) |
|
| Controls how the attribute can be modified |
|
| Controls when the attribute appears in responses |
|
| Uniqueness constraint (only |
|
| Whether string comparisons are case-sensitive. Note: since only |
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
mutabilityerror.writeOnly - The attribute can be set in requests but is never returned in responses.
Note:
readOnlymutability 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, useimmutableinstead.
Returned Rules
default - The attribute is returned by default in all responses, unless excluded via the
excludedAttributesquery 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
attributesquery 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/SchemasResponse (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:UserReturns 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 Requestand amutabilitySCIM 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:employmentIdFor sub-attributes of complex attributes, use dot notation:
urn:ietf:params:scim:schemas:extension:customapp:2.0:User:department.namePATCH 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:employmentIdThis 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:UserExclude Extension Attributes
GET /scim/v2/Users/{userId}?excludedAttributes=urn:ietf:params:scim:schemas:extension:customapp:2.0:User:departmentSub-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.nameThis 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
schemasarray.The
schemasarray 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.dateTimevalues must conform to ISO 8601 format (e.g.,2025-01-15T10:30:00Z).referencevalues must be valid absolute URIs or absolute paths.binaryvalues must be valid base64-encoded strings.
Required Attribute Validation
On create (POST) and replace (PUT), all attributes marked
required: truemust 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,
replaceandremoveoperations 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
removeoperation.Required sub-attributes within complex attributes cannot be removed.
Immutable attributes cannot be removed via a
removeoperation.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 |
|---|---|---|
| 400 | Attribute value does not match the expected type, a required attribute is missing/null, or an unsupported schema is referenced |
| 400 | An attribute is not defined in the schema, extension data is not an object, or sub-attributes are not recognized |
| 400 | An immutable attribute was modified on PUT or PATCH |
| 400 | A filter expression was used in a PATCH path for extension attributes (not supported) |
| 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 |
|---|---|
| A user is created via SCIM |
| A user is updated via SCIM (PUT or PATCH) |
| 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 theuserobject only if the user has extension data. Theschemasarray 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"
}
}