SCIM Service API
SCIM 2.0 provisioning service for Inspectorio products.
It is based on the SCIM 2.0 protocol (RFC 7644) and schema (RFC 7643) specifications.
This API enables Identity Providers (e.g. Microsoft Entra ID; also compatible with any SCIM 2.0 client) to automate user provisioning and deprovisioning across RSC, QRM, and Digital Assets Management.
If you are configuring Microsoft Entra ID, follow the step-by-step Entra ID SCIM Configuration Guide β this document is the reference for the underlying API.
Getting Started
- Authenticate β Include your Secret Token in the
Authorizationheader of every request as an HTTP Bearer token:Authorization: Bearer <your-secret-token> - Discover roles β
GET /v2/{product}/UserOrganizationRolesto retrieve available role IDs for your product. Replace{product}with your product path prefix:rise(RSC),sight(QRM), ordocuflow(Digital Assets Management). Role IDs are environment-specific β always callGET /UserOrganizationRolesagain when you move between pre-production and production. Hardcoding role IDs across environments is unsupported. - Create users β
POST /v2/{product}/Userswith a JSON body. The minimum payload accepted by this service is{ userName, roles }βdisplayNameis optional but strongly recommended (when omitted the user record is created with empty first/last name fields); other SCIM attributes are accepted on input but ignored. See the example below. - Manage users β
GET(list/filter),PATCH(update attributes),DELETE(remove/deactivate). - Minimal integration β Most Identity Providers only need
POST(idempotent upsert; creates or updates) andDELETE(remove/deactivate per product).PUTandPATCHare supported for finer-grained control but are not required for a complete provisioning lifecycle. See Recommended minimal integration below.
Example body for step 3 (POST /v2/{product}/Users):
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"displayName": "Jane Doe",
"roles": [{ "value": "<role-id-from-step-2>" }]
}
Authentication
Entra ID admins: follow the step-by-step Entra ID SCIM Configuration Guide (formerly Azure AD).
SCIM endpoints require an Inspectorio Secret Token in the Authorization header, sent as an HTTP Bearer token. Secret Tokens are tenant-specific and issued by your Inspectorio Account Manager or Customer Success Manager (CSM) during onboarding. Your token is scoped to your tenant ecosystem β the Inspectorio organization(s) your company has been set up with; all user listings and mutations operate within that scope. Example:
Authorization: Bearer <your-secret-token>
Secret Tokens do not expire β the token can be used indefinitely unless there is a specific need to renew it. Renewal is on-demand only; contact your CSM when you need to rotate.
Tenant URL & product endpoints
Tenant URL
Configure your Identity Provider with the SCIM base URL pattern:
https://scim.{env}.inspectorio.com/v2/{product}/
Where {env} is pre for pre-production or omitted (e.g. scim.inspectorio.com) for production, and {product} is rise, sight, or docuflow. The base URL ends with /v2/{product}/ β a trailing slash is required. The service does not normalize URLs: joining a trailing-slash base with a leading-slash path produces a double slash (/v2/sight//Users) and returns 404, exactly like a missing separator (/v2/sightUsers) β append resource names without a leading slash.
Microsoft Entra ID only: paste the URL above with ?aadOptscim062020 appended into the Tenant URL field in Entra ID Provisioning β that query parameter opts Entra ID into its compliant SCIM 2.0 behavior. Other identity providers should use the base URL without the query string. Because the Tenant URL is product-specific, create one Entra Enterprise Application per Inspectorio product you provision to.
Product endpoints
Each product has its own set of SCIM resources under a dedicated path prefix:
| Product | Path prefix | User ID format | Role ID format |
|---|---|---|---|
| RSC | /rise/ | UUID | UUID |
| QRM | /sight/ | Integer (passed as a JSON string) | Integer (passed as a JSON string) |
| Digital Assets Management | /docuflow/ | UUID | UUID |
Your Secret Token determines which products you have access to. Calling a product endpoint that is not configured for your tenant returns 403 with detail Tenant is not configured for {Product}.
Note (product names in error messages): error messages returned by the API refer to products by their API names β Rise (RSC), Sight (QRM), Docuflow (Digital Assets Management). For example, the 403 detail reads
Tenant is not configured for Docuflow.
Only the endpoints listed in this document are supported: GET /v2/Me and POST /v2/Bulk return 501, and write verbs on /UserOrganizationRoles return an error (the role catalog is read-only). POST /v2/{product}/Users/.search (RFC 7644 Β§3.4.3) is available as a POST alternative to GET with a filter β see its endpoint documentation for caveats.
Content types
Responses are always served as application/scim+json per RFC 7644 Β§3.1. Request bodies with Content-Type: application/scim+json (recommended) and application/json are both accepted and parsed identically. Any other content type (e.g. text/plain) leaves the body unparsed: write requests return 400 with a generic error (Cannot read properties of undefined (reading 'roles')). For POST /Users/.search the consequence is different and worth knowing β see the .search endpoint documentation.
Users created via this API
Users provisioned through SCIM are SSO-only β they can authenticate only via your organization's configured SSO method (e.g. Microsoft Entra ID) and cannot log in with username/password: no password credential is ever created for them, and a password login attempt returns a generic 400 Invalid email or password (indistinguishable from a wrong password).
On production, a successful POST /Users may send a first-access email to the user (the SCIM create auto-accepts the invitation on all three products β the email is a notification only; no click is required). There is no SCIM-side API to check delivery status or re-send it. If a user reports they did not receive it, the admin should re-send it through the product UI (RSC, QRM, or Digital Assets Management web app).
Existing password-login users
If you roll SCIM out to users who already have a manual password login with the same email: on RSC and Digital Assets Management, a provisioning update that targets such a pre-existing password-login user removes that account and re-creates it as an SSO-only account (the displayName from the request is applied, and the user receives a new id). Password-only users do not appear in GET /Users, so you will not see the collision coming β plan the migration accordingly.
Recommended minimal integration
Most Identity Providers only need to implement two of the eight verbs:
POST /v2/{product}/Usersβ idempotent upsert. Creates the user if they do not exist; updatesrolesif they do. Returns 201 in both cases. POST always results inactive: trueβ the request body'sactivevalue is ignored on POST, and on QRM and Digital Assets Management a POST on an INACTIVE user reactivates them (even if the body saysactive: false). UsePATCH/PUT/DELETEto deactivate.DELETE /v2/{product}/Users/{id}β removes or deactivates the user. Exact semantics vary per product (see Status Mapping below).
PUT and PATCH are supported for finer-grained control (e.g. updating roles without touching active) but are not required for a complete provisioning lifecycle.
Note (lookup before PUT/DELETE): Use
GET /v2/{product}/Users?filter=userName eq "[email protected]"(URL-encoded) to recover a user'sidbefore aPUTorDELETE. See SCIM Filter Syntax below for the encoding rules.
SCIM Filter Syntax
Use the filter query parameter to search resources. Syntax: <attribute> <operator> <value>
URL encoding
Filter values are URL query-string parameters and must be URL-encoded. Common substitutions:
| Raw | Encoded |
|---|---|
| space | %20 (or +) |
" (quote) | %22 |
@ (at sign) | %40 |
Example. To find a user by email, the raw filter:
filter=userName eq "[email protected]"
becomes the encoded query string:
?filter=userName%20eq%20%22user%40example.com%22
A worked curl command:
curl -H 'Authorization: Bearer <token>' \
'https://scim.pre.inspectorio.com/v2/sight/Users?filter=userName%20eq%20%22user%40example.com%22'
Note: A filter with a syntax error (e.g. an unterminated quote or a truncated operator) returns 400 with
scimType: invalidFilterand a parse message. A filter consisting of an attribute with no operator at all (e.g.?filter=userName) currently returns 500 with a genericCannot read properties of undefined (reading 'toLowerCase')message β useuserName prto test for presence. Encode all special characters anyway.
Supported Operators
| Operator | Description | Example |
|---|---|---|
eq | Equal | userName eq "[email protected]" |
ne | Not equal | userName ne "[email protected]" |
co | Contains | displayName co "Jane" |
sw | Starts with | userName sw "jane" |
ew | Ends with | userName ew "@example.com" |
gt | Greater than | userName gt "j" |
ge | Greater than or equal | userName ge "j" |
lt | Less than | userName lt "z" |
le | Less than or equal | userName le "z" |
pr | Present (has any value) | userName pr |
Logical operators and, or, and not are supported per RFC 7644 Β§3.4.2.2. Example: userName sw "jane" and active eq true (use lowercase values in compound filters β see the case-sensitivity note below).
Filterable Attributes
| Endpoint | Filterable attributes |
|---|---|
/{product}/Users | userName, displayName, active, id |
/{product}/UserOrganizationRoles | display, id |
Note (unsupported attributes): Filtering on
name.givenName,name.familyName, oremails[β¦]is accepted by the parser but always returns zero matches β those fields are not persisted by this service.
Note (string case-sensitivity): Always send lowercase filter values. The rules:
- Simple filters (a single comparison): the value is lowercased before matching, so
userNameemail lookups are case-insensitive. Caveat: only the filter value is lowercased β storeddisplayNamevalues with mixed case may not match.- Compound filters (
and/or/not): values are compared verbatim. A mixed-case value underand/orsilently matches nothing; undernotit matches everyone (the inner comparison fails for every user, so the negation includes them all).UserOrganizationRolesfilters: values are never lowercased.
Note (boolean filters): Use unquoted boolean literals for
active:active eq true,active eq false. Quoted strings likeactive eq "true"are compared against the boolean attribute as strings and never match.
Attribute Mapping Referenceβ
This section documents how SCIM 2.0 attributes from the Identity Provider (e.g. Microsoft Entra ID) are mapped to each downstream product: RSC, QRM, and Digital Assets Management.
Microsoft Entra ID role mapping (Entra ID-specific)
This section applies only to Microsoft Entra ID setups. In Entra ID, each Enterprise Application defines App roles, each with a Display name and a Value. To provision a user with a given product role, the App role Value must equal the internal product role ID returned by GET /{product}/UserOrganizationRoles.
| Entra ID App role field | Maps to SCIM | Source of truth |
|---|---|---|
| Display name | roles[].display | Cosmetic only β overwritten on read by the product's role name |
| Value | roles[].value | Must equal the role id returned by GET /{product}/UserOrganizationRoles |
For QRM, role IDs are integers but the SCIM schema requires them to be sent as JSON strings β e.g. configure Entra App role Value as "4", not 4.
Microsoft Entra ID Attribute Mapping (Entra ID-specific)
The full Entra ID setup walkthrough is in the Entra ID SCIM Configuration Guide. The four attribute mappings required for SCIM provisioning are:
| Target (SCIM) | Entra ID expression | Notes | Required | Multi-value |
|---|---|---|---|---|
userName | userPrincipalName | User's email (primary identifier) | yes | no |
active | Not([IsSoftDeleted]) | Deactivate on Entra ID soft-delete | yes | no |
displayName | displayName | Full name (split into first/last) | yes | no |
roles | AppRoleAssignmentsComplex([appRoleAssignments]) | All assigned app roles for the user | yes | yes |
Remove all other attribute rows from the Entra ID provisioning mapping. Mark userName, active, displayName as Required in Entra ID's advanced attribute settings; the roles attribute is added manually with type String, Required, Multi-Value.
App role Value fields in Entra ID must equal the role id returned by GET /{product}/UserOrganizationRoles for the target environment. For QRM (integer IDs), enter the role ID as a string β e.g. "4", not 4. App role Values are environment-specific: use a separate Enterprise Application per environment (or update every App role Value) when moving from pre-production to production.
Note (Digital Assets Management): assign each user exactly one App role in the Enterprise Application β multiple assignments provision multiple roles, and the request is rejected with 400.
Note (name changes): name changes made in your IdP after creation do not propagate β the update succeeds with no effect on the stored name. To force a name update, delete and re-create the user (the re-created user receives a new
id).
User Attribute Mapping
| SCIM Attribute | Description | RSC | QRM | Digital Assets Management |
|---|---|---|---|---|
userName | User email (primary identifier) | email (lowercase, trimmed) | email (lowercase, trimmed) | email (lowercase, trimmed) |
displayName | Full name of the user | Split into firstName + lastName | Split into first_name + last_name | Split into firstName + lastName |
active | Whether the user is active | true β ACTIVE; false β see Status Mapping | true β ACTIVE; false β see Status Mapping | true β ACTIVE; false β see Status Mapping |
roles[].value | Role identifier | UUID string (multiple roles supported) | Integer-as-string (multiple roles supported) | UUID string (exactly one role required) |
roles[].display | Role display name (input) | Same for all products β see note below | Same for all products β see note below | Same for all products β see note below |
emails[].value | Email addresses | Not used (uses userName) | Not used (uses userName) | Not used (uses userName) |
name.givenName | First name | Not used (uses displayName) | Not used (uses displayName) | Not used (uses displayName) |
name.familyName | Last name | Not used (uses displayName) | Not used (uses displayName) | Not used (uses displayName) |
id | SCIM resource ID (read-only) | Product user UUID | Product user ID (integer-as-string) | Product user UUID |
Note (
roles[].display): the input value is cosmetic β on responses,displayis overwritten with the product's role name for the role ID. Role IDs the product no longer recognizes are omitted from write responses.
Data Transformations
Inspectorio applies the following normalizations automatically β no customer action is required.
| Transformation | Rule | Example |
|---|---|---|
| Email normalization | Converted to lowercase and trimmed | " [email protected] " β "[email protected]" |
| Display name normalization | Leading/trailing whitespace trimmed; consecutive internal spaces collapsed to one | "Jane van Doe" β "Jane van Doe" |
| Display name parsing | Split on first space; if single word, used for both first and last name | "Jane Doe" β firstName: "Jane", lastName: "Doe" |
| Multi-word last names are preserved | "Jane van Doe" β firstName: "Jane", lastName: "van Doe" | |
| Single name is duplicated | "Jane" β firstName: "Jane", lastName: "Jane" | |
| Role addβreplace rewrite | Some Entra ID provisioning flows emit op: "add" on the roles path. Inspectorio rewrites those to replace to keep the operation idempotent. | op: "add", path: "roles" β op: "replace", path: "roles" |
| Boolean-path PATCH rewrite | Some Entra ID provisioning flows emit PATCH ops where path is the literal string "true" or "false". Inspectorio rewrites those to path: "active" with the corresponding boolean value. | op: "replace", path: "false" β op: "replace", path: "active", value: false |
Status Mapping
How active translates into customer-observable behavior on each product:
Reversible deactivation (QRM, Digital Assets Management Admin/User):
PATCH /v2/{product}/Users/{id}
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{ "op": "replace", "path": "active", "value": false }]
}
To reactivate, send the same payload with "value": true. The user remains in GET /Users responses with "active": false.
Permanent removal (RSC always; QRM via DELETE; Digital Assets Management Visitor):
DELETE /v2/{product}/Users/{id}
SCIM active | RSC | QRM | Digital Assets Management |
|---|---|---|---|
true | ACTIVE β appears in GET /Users | ACTIVE β appears in GET /Users | ACTIVE β appears in GET /Users |
false | Permanently removed β see RSC notes | Deactivated (INACTIVE) β see QRM notes | Visitor removed; Admin/User deactivated β see notes |
| (on create) | ACTIVE (invitation auto-accepted) β see RSC notes | ACTIVE (auto-accepted) | ACTIVE (auto-accepted) |
| (reactivation) | Not supported β see RSC notes | PATCH active=true or POST upsert β see QRM notes | PATCH active=true or POST upsert β see notes |
RSC notes:
active=falsepermanently deletes the user from the organization. The PATCH response returns 200 echoingactive: false, but theidis dead immediately β a subsequentGET /Users/{id}returns 404 and the user is gone from the list.- On a not-yet-activated (PENDING) invitee,
PATCH active=falsereturns 404 and removes nothing β useHTTP DELETEto remove a pending invitation. - On create, the invitation is issued and auto-accepted within the same request, so the user is
ACTIVEimmediately in both the list and by-idGET. If auto-activation fails, the invitation remains PENDING and is invisible toGET(list and by-id); it can still be removed viaDELETE /Users/{id}. - Reactivation is not supported:
PATCH active=trueon a removed user returns 404. Re-create the user via POST β the re-created user receives a newid(the old id never resolves again).
QRM notes:
PATCH active=falsedeactivates the user (INACTIVE); they remain inGET /Userswithactive: falseand can be reactivated.- Session invalidation on deactivation follows the product's own behavior. To guarantee immediate session revocation, use
HTTP DELETEβ it revokes the user's active sessions and removes the user permanently (no longer queryable). - Reactivation may fail with 409 if the organization user quota is exceeded.
Digital Assets Management notes:
- Visitor semantics apply to the role whose display name is exactly
Visitor(case-sensitive).active=falseorHTTP DELETEon a Visitor permanently removes them. - Admin/User accounts deactivate to
INACTIVEand remain inGET /Userswithactive: falsefor audit and reactivation. HTTP DELETEon an already-INACTIVE Admin/User is an idempotent no-op (204).- Quota errors on reactivation currently surface as 500 (asymmetric with QRM's 409).
Note (role updates): Role assignment via
PATCH/PUTupdates the user's role in the product. After a role change, the user must sign out and back in before newly granted areas of the product become visible; some products may require additional setup steps outside SCIM. Inspectorio cannot guarantee a role update alone grants immediate access.
Role Handling Per Product
| Aspect | RSC | QRM | Digital Assets Management |
|---|---|---|---|
| Multiple roles | Supported | Supported | Exactly one role per user is required for Digital Assets Management |
| Role ID format | UUID string | Integer, sent as a JSON string (e.g. "4") | UUID string |
| Visitor downgrade | β (Visitor role only exists in Digital Assets Management) | β (Visitor role only exists in Digital Assets Management) | Not allowed (cannot downgrade an Admin/User to Visitor) |
| Empty roles | At least one role required | At least one role required | Exactly one role required |
Note (identifying the Visitor role): Visitor semantics apply to the Digital Assets Management catalog role whose display name is exactly
Visitor(case-sensitive); a differently named role is treated as a regular Admin/User role.
Note: A
POST /Userswithout at least one role returns 400 with a message containing the word "role". Some IGA systems swallow this 400 and report "no invite sent" β make sure your IGA surfaces the SCIM error.
Authenticationβ
- HTTP: Bearer Auth
Security Scheme Type: | http |
|---|---|
HTTP Authorization Scheme: | bearer |