Skip to content

SCIM User Provisioning

If your organization manages people in Microsoft Entra ID (Azure AD), you can provision them into Ditio automatically instead of maintaining users in two places. Ditio supports the SCIM 2.0 protocol: when someone joins, changes details, or leaves in your directory, the change flows into Ditio on the next provisioning cycle.

  • Creates new Ditio accounts when people join your team or organization. New users get the base User role; give other roles in Ditio Web.
  • Updates user profiles when changes are made in Entra ID
  • Deactivates Ditio accounts when people leave the team or organization
  • Group provisioning is not supported
  • Roles are not provisioned: Entra ID app roles don’t reach Ditio
  • Write-back from Ditio to Entra ID is not supported
  1. An Entra ID (Azure AD) tenant with an active subscription
  2. A Ditio company already registered
  3. Your Azure Tenant ID sent to Ditio — we need it to issue the token for your tenant

The SCIM endpoint (the “Tenant URL” in Azure’s provisioning setup) is https://integration.ditio.no/scim in production and https://core-api.ditio.dev/scim in test; see Environments. Existing setups that use the endpoint URL Ditio sent earlier keep working and need no change.

Send your Azure Tenant ID to [email protected]. Ditio issues a token for your tenant and sends it to you separately. You paste it into Azure as the Secret Token; there is nothing else to fetch or exchange.

Use the test endpoint to verify attribute mappings against test data before provisioning into production.

  1. Sign in to the Azure Portal
  2. Go to Enterprise Applications → select your Ditio application
  3. Go to the Provisioning configuration page
  4. Set Provisioning Mode to Automatic
  5. Under Admin Credentials, enter the SCIM endpoint URL above as the Tenant URL and the token Ditio sent you as the Secret Token

For detailed instructions, see Microsoft’s guide: SCIM provisioning with Entra ID.

Ensure the following attributes are mapped correctly in Entra ID.

A user is created only when all three of these are present. If one is missing, provisioning fails for that user and the Azure provisioning log shows the error.

Entra ID attributeSCIM attributeDescription
userPrincipalNameuserNameEmail address
displayName (plus givenName, surname)displayName (plus name.givenName, name.familyName)The user’s name. Always map displayName: later updates take the name from it. A new user gets name.givenName + name.familyName when both are sent; otherwise displayName is split into first and last name at the first space
telephoneNumber, mobilephoneNumbers[type eq "work"].value, phoneNumbers[type eq "mobile"].valueAt least one phone number, which must be a valid phone number. See Phone numbers

Also map active (Entra ID: Switch([IsSoftDeleted], ...)). It isn’t required to create a user, but it is what enables and disables the user in Ditio when they leave.

Ditio reads the numbers by their primary flag, not by their type:

  • The number marked primary becomes the user’s work mobile.
  • The first number not marked primary becomes the private mobile.
  • The work mobile is the user’s sign-in phone number in Ditio. If there is no primary number, the private mobile is used instead.
Entra ID attributeSCIM attributeDescription
employeeIdurn:...:enterprise:2.0:User:employeeNumberEmployee number. Must be unique within the company when set
Extension attributeurn:...:ditio:1.0:User:birthDateDate of birth. When it is missing or not in a supported format, a new user gets the 1st of the current month as birth date
Extension attributeurn:...:ditio:1.0:User:employmentStartDateEmployment start date. When missing, Ditio keeps the start date of the user’s current employment, or uses the 1st of the current month for a new user
jobTitletitleWork title
departmenturn:...:enterprise:2.0:User:departmentDepartment on the employment
Extension attributeurn:...:enterprise:2.0:User:costCenterSets “Main project number” on the employment
Extension attributeurn:...:ditio:1.0:User:employmentEndDateEmployment end date (terminates the employment)
Extension attributeurn:...:ditio:1.0:User:builderCardBuilder card ID
Extension attributeurn:...:ditio:1.0:User:builderCardExpirationDateBuilder card expiration date
Extension attributeurn:...:ditio:1.0:User:payrollConnectedtrue = hourly paid, false = fixed salary
Extension attributeurn:...:ditio:1.0:User:workTimeArrangementWork time arrangement table
Extension attributeurn:...:enterprise:2.0:User:organizationOrganization number (which Ditio company to create the user in)
Extension attributeurn:...:ditio:1.0:User:tagsAssigns and removes tags, e.g. "Skilled worker:true,Apprentice:false". See Syncing tags
managerurn:...:enterprise:2.0:User:manager.valueSets the user’s nearest manager. The value must be the Entra Object ID of an existing Ditio user; the resolved user becomes the primary immediate supervisor. Existing non-primary supervisors are preserved. Removing the attribute does not clear an existing supervisor.
  • dd.MM.yyyy (e.g. 15.01.2026)
  • ddMMyyyy (e.g. 15012026)
  • yyyy-MM-dd (e.g. 2026-01-15)

The tags attribute assigns and removes Ditio tags on the user. Map it as a single string attribute, not as a multi-valued one. The value is a comma-separated list of TagName:true / TagName:false pairs:

Skilled worker:true,Apprentice:false,Safety course:true
ValueEffect
TagName:trueAssigns the tag. No effect if the user already has an assignment of that tag, including one that has expired or has not started yet
TagName:falseRemoves every assignment of that tag from the user
TagName or TagName: (no value)Assigns the tag
  • Only the tags you list are changed. Tags that are not listed are left as they are, and clearing or unmapping the attribute removes nothing — a tag stays until you send it as TagName:false.
  • Names are matched against the tags that already exist in the company, ignoring case and spaces, so Safety course and safetycourse are the same tag.
  • Only true, in any casing, assigns. Every other value, including 1, counts as false.
  • Avoid : in tag names — it separates the name from the value.
  • Empty entries are ignored, so a trailing comma or a ,, from a sparse mapping expression costs you nothing.

Payroll tags are assigned and removed through the same attribute. What SCIM cannot do is create one: on an assignment, if the name matches no existing tag it creates an ordinary tag instead, and the payroll effect silently never happens. Create the payroll tag in Ditio first, then map it.

Four constraints are worth knowing before you map one:

  • The tag must exist in the company the user is provisioned into. The organization attribute routes each user into the company holding that organization number — your main company or one of its subsidiaries. A tag on the main company is not matched for a user in a subsidiary, so create the payroll tag in every company you provision into.
  • Assigning one does not trigger a recalculation. A tag assigned over SCIM carries no dates, so Ditio queues no recalculation of days that are already calculated, and the tag takes effect for days calculated from then on. Because it has no start date, an older day recalculated later for some other reason will pick the tag up as well. Assign the tag in Ditio, or through Employees API v5 with a from-date, when earlier days must be recalculated straight away.
  • TagName:false removes every assignment of that tag, including date-ranged assignments created through Employees API v5. Removing a date-ranged payroll assignment does queue a recalculation of the days it covered — up to 60 days back.
  • Do not manage the same tag from both surfaces. PUT /api/v5/integration/employees/{employeeNumber}/tags replaces the employee’s whole tag list and removes SCIM-assigned tags it omits.

Tags assigned through SCIM carry no validity period. Use the Employees API v5 if you need a payroll tag with a from/to date.

Extension attributes (for fields like birthDate and employmentStartDate) can be added in two ways.

Option 1: use existing extension attributes

Terminal window
Set-ADUser -Identity "anyUser" -Add @{extensionAttribute4="myString"}

Option 2: create custom extension attributes

See Microsoft’s guides:

Setting extension values:

Terminal window
Set-AzureADUserExtension `
-ObjectId {objectId} `
-ExtensionName extension_{your_extension_id}_BuilderCardId `
-ExtensionValue "Builder Card Value"

Reading all user properties including extensions:

Terminal window
(Get-AzureADUser -ObjectId {objectId}).ToJson()

Test with individual users before running a full provisioning cycle:

  1. Go to Enterprise Applications → your Ditio app → Users and Groups
  2. Add a few test users
  3. Use Azure’s on-demand provisioning to provision them manually
  4. Verify the users appear correctly in Ditio
  5. Once confirmed, enable automatic provisioning for all users
IssueCauseFix
Provisioning fails for a userA required attribute is missing (userName, a name, or a phone number), or the phone number isn’t validCheck the provisioning log in Azure; fill the attribute in Entra ID
Users get a placeholder birth date or start datebirthDate or employmentStartDate isn’t mapped, or isn’t in a supported formatMap the attribute and send one of the supported formats
Wrong number used to sign inThe sign-in number is the one marked primary, not the one with type workSee Phone numbers
Duplicate employee numberemployeeId already in use in the Ditio companyEmployee numbers must be unique within a company — correct the conflicting value
User lands in the wrong companyorganization attribute doesn’t match a Ditio company organization numberVerify the organization number mapping with Ditio support
Nothing happens after setupProvisioning cycle hasn’t run yetAzure runs cycles roughly every 40 minutes; use on-demand provisioning to test immediately
A payroll tag has no effectThe name didn’t match an existing payroll tag (an ordinary tag was created instead); or the tag exists on the main company but the user was provisioned into a subsidiary; or the affected days were already calculatedCreate the payroll tag in the company the user lands in, check the name in the mapping, and re-check days that were already calculated
  • If your HR system (not Entra ID) is the master, use the Employees API v5 instead
  • For sign-in (not provisioning) with Microsoft accounts, see Azure AD SSO