SCIM provisioning
SCIM provisioning makes your identity provider the source of truth for who exists in a LedgerBee company and what they can do. The IdP pushes users and groups over SCIM 2.0; each group's effect is configured in LedgerBee under Settings → Access → User provisioning and is never writable over the protocol.
A synced user is an identity with no rights of its own. Group membership decides what it materializes:
- Employee record — the person appears in the employee directory and flows into payroll where that integration is connected.
- App access — the person gets a LedgerBee account, can sign in, and holds the roles and admin rights their groups grant.
A group can do either, both, or neither. A user provisioned only through an app-access group never becomes an employee, and an employee never requires app access.
Endpoint and authentication
The SCIM 2.0 base URL is https://api.ledgerbee.com/api/v1/scim. Every request
carries the provisioning token as a bearer token:
Code
The token identifies the company, so no company identifier appears in any request path or body.
Generate it under Settings → Access → User provisioning. It is displayed
once. The Provisioning status toggle suspends provisioning while keeping the
token valid; every request returns 403 while it is off. Revoking the token
invalidates it permanently.
These endpoints implement a protocol rather than the REST API, so they are not part of the generated API Reference. The tables below are the contract.
Supported operations
| Resource | Operations |
|---|---|
| Users | POST /Users, GET /Users, GET /Users/{id}, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id} |
| Groups | POST /Groups, GET /Groups, GET /Groups/{id}, PUT /Groups/{id}, PATCH /Groups/{id}, DELETE /Groups/{id} |
| Discovery | GET /ServiceProviderConfig, GET /ResourceTypes, GET /Schemas, GET /Schemas/{id} |
Support matrix
| Capability | Supported | Detail |
|---|---|---|
PATCH | Yes | Path-based and pathless replace forms |
| Filtering | Partial | eq only, on userName and externalId for Users, displayName and externalId for Groups |
| Pagination | Yes | startIndex and count; count is capped at 200 per page |
| Bulk operations | No | Send individual requests |
| Sorting | No | |
| ETag | No | |
| Password sync | No | A password is never accepted over SCIM |
Group-driven provisioning
Groups pushed by the IdP appear under Provisioned groups. Opening a group exposes four settings:
| Setting | Effect on members |
|---|---|
| Provision employees | An employee record is created. Leaving the group never removes it. |
| Grant app access | Not available yet. Will create a LedgerBee account the member can sign in with. |
| Roles | Not available yet. Will grant the permissions of the selected roles. |
| Grant admin | Not available yet. Will make the member an administrator of the company. |
App access arrives with single sign-on. The last three settings depend on a
provisioned member being able to authenticate, which needs the per-tenant
sign-on flow that ships next; enabling them returns
400 SCIM_APP_ACCESS_NOT_AVAILABLE. Until then a group provisions employee
records, and app accounts are created by invitation from the Users settings.
Grants combine additively across groups: a member of two app-access groups holds the union of both role sets, and is an admin when either group grants admin. Group-derived grants are tracked separately from roles assigned by hand, so removing someone from a group withdraws exactly what that group gave and leaves manual assignments untouched. The Users list marks group-derived roles and flags accounts that SCIM created.
Losing membership of every app-access group deactivates the SCIM-created account and ends its live sessions within the access-token lifetime. An account created by invitation keeps its access and loses only the group-derived grants.
Employee records are retained
A group change never removes an employee record, because bookkeeping records reference employees. An employee is deactivated only when the IdP marks the user inactive.
Only Provision employees creates one. A user whose groups carry Provision app access alone receives an app account and no employee record.
Provisioning lifecycle
| Phase | What happens |
|---|---|
| Create | POST /Users stores the identity. Employee and app-access projections are applied from current group membership. |
| Update | PUT or PATCH /Users/{id} updates the identity, mirrors changed attributes onto a linked employee record, and re-applies projections. |
| Group change | A membership PATCH on /Groups/{id} re-applies projections for every affected member. |
| Deactivate | active: false or DELETE /Users/{id} deactivates the account, ends live sessions, and marks a linked employee inactive. The record is retained. |
Microsoft Entra ID
- Open the LedgerBee enterprise application in the Microsoft Entra admin center. Create one through Enterprise applications → New application → Create your own application if none exists.
- Open Provisioning and select Automatic.
- Set Tenant URL to
https://api.ledgerbee.com/api/v1/scimand Secret Token to the generated token. - Select Test Connection, then Save.
- Keep the default attribute mappings. LedgerBee reads
userName,active,name.givenName,name.familyName,title,externalId, and the work entries ofemails,phoneNumbers, andaddresses. - Enable group provisioning, then assign the groups to sync under Users and groups.
- Set Provisioning Status to On.
Entra provisions on a fixed cycle of roughly 40 minutes. Provision on demand applies a single user immediately. Repeated failures quarantine the provisioning job, which is why a token change should use rotation with a grace window rather than a revoke.
Map objectId to externalId for Microsoft sign-in
LedgerBee stores a provisioned user's externalId as their Microsoft object id
when it creates the account, which is what lets them sign in with Microsoft
without a separate invitation. That only works when externalId carries the
object id: Entra's default mapping sends mailNickname, which is not an
object id, and LedgerBee ignores it rather than storing a value that cannot
match a sign-in.
In Provisioning → Mappings → Provision Microsoft Entra ID Users, edit the
attribute whose customappsso target is externalId and set its source to
objectId. Users provisioned before the change keep no object id — they link on
their first Microsoft sign-in instead.
Okta
- Open the LedgerBee application in the Okta admin console, select Provisioning, then Configure API Integration.
- Enable Enable API integration, set the base URL to
https://api.ledgerbee.com/api/v1/scim, and paste the token as the API token. - Select Test API Credentials, then Save.
- Under To App, enable Create Users, Update User Attributes, and Deactivate Users.
- Set the unique identifier field for users to
userName. Okta resolves existing users withGET /Users?filter=userName eq "...". - Push each group to sync from the Push Groups tab. Assigning a group to the application does not push it.
Okta imports users in pages of 100. Unlinking a pushed group offers to delete it in the target application, which removes the group from LedgerBee and withdraws the app access it granted.
Deprovisioning
| Event in the IdP | Effect in LedgerBee |
|---|---|
User deactivated (active: false) | Account deactivated, live sessions ended, linked employee marked inactive |
| User deleted from the application | Treated as deactivation; records are retained, never hard-deleted |
| Removed from every app-access group | SCIM-created account deactivated; invited accounts keep access and lose group-derived grants |
| Removed from an employee-flagged group | No effect on the employee record |
| Group deleted | Members lose the app access and roles that group granted |
Errors & failure states
Errors use the SCIM error schema, with the code below in detail.
| Condition | What you observe | Fix |
|---|---|---|
| Missing or wrong token | 401 SCIM_INVALID_TOKEN | Re-copy the token, or generate a new one |
| Provisioning toggled off | 403 SCIM_CONNECTION_DISABLED | Enable Provisioning status |
| Unsupported filter attribute or operator | 400 SCIM_INVALID_FILTER | Use eq on a supported attribute |
| Malformed patch body or unsupported operation | 400 SCIM_INVALID_PATCH | Correct the operation shape |
| Unknown user id | 404 SCIM_USER_NOT_FOUND | Re-resolve the user by externalId filter |
| Unknown group id | 404 SCIM_GROUP_NOT_FOUND | Re-push the group |
| Unknown schema URN | 404 SCIM_SCHEMA_NOT_FOUND | Request a URN listed by GET /Schemas |
Duplicate externalId or work email | 409 SCIM_DUPLICATE_USER | Resolve the existing user and update it |
Duplicate group externalId | 409 SCIM_DUPLICATE_GROUP | Resolve the existing group and update it |
| Rate limited | 429 with Retry-After | Honour Retry-After and back off |
Troubleshooting
Test Connection fails. Confirm the base URL ends in /api/v1/scim, the
token was pasted whole, and Provisioning status is enabled.
Users sync but no groups appear. In Entra, group provisioning must be enabled and the groups assigned to the application. In Okta, groups must be pushed from the Push Groups tab.
A member of the right group has no access. Confirm the group has Grant app access enabled. A membership pushed before the user existed in LedgerBee is skipped, so re-push that group.
A user cannot sign in with Microsoft. The Microsoft identity is linked only on accounts SCIM creates. An account that already existed connects Microsoft sign-in once from its own profile.
SSO enforcement
SSO enforcement, in the same settings tab, controls how members sign in:
| Mode | Effect |
|---|---|
| Off | Any sign-in method works |
| Optional | Any method works; use this while rolling out SSO |
| Required | Only sign-in through the identity provider reaches the company. Password, passkey, Google, and Apple sessions lose access. |
Required can only be enabled from a session already signed in through the identity provider, so enabling it cannot lock out the administrator who sets it. It does not apply to advisor firms granted access — those are governed by the grant under Advisors.