# Directory sync with SCIM 2.0

> Generate and revoke a CADABRA SCIM token, the endpoint and requests that are implemented, what provisioning and deprovisioning change, and what SCIM does not sync.

URL: https://cadabrai.com/docs/team/directory-sync/
Updated: 2026-08-28

---

- Getting started [Overview](https://cadabrai.com/docs/getting-started/)
- [Install](https://cadabrai.com/docs/getting-started/install/)
- [Your First Prompt](https://cadabrai.com/docs/getting-started/first-prompt/)
- [How It Works](https://cadabrai.com/docs/getting-started/how-it-works/)

### Modes

- [Overview](https://cadabrai.com/docs/modes/)
- [All Modes](https://cadabrai.com/docs/modes/all-modes/)
- [Ask Mode](https://cadabrai.com/docs/modes/ask-mode/)
- [Plan Mode](https://cadabrai.com/docs/modes/plan-mode/)
- [Agent Mode](https://cadabrai.com/docs/modes/agent-mode/)
- [Drawings Mode](https://cadabrai.com/docs/modes/drawings-mode/)
- [Debug Mode](https://cadabrai.com/docs/modes/debug-mode/)
- [Imagine Mode](https://cadabrai.com/docs/modes/imagine-mode/)

### Prompts

- [Overview](https://cadabrai.com/docs/prompts/)
- [Writing Prompts](https://cadabrai.com/docs/prompts/writing-prompts/)
- [Prompt Library](https://cadabrai.com/docs/prompts/prompt-library/)
- [Attachments](https://cadabrai.com/docs/prompts/attachments/)
- [Drawing to CAD](https://cadabrai.com/docs/prompts/drawing-to-cad/)

### Standards

- [Overview](https://cadabrai.com/docs/standards/)
- [Drawing Standards](https://cadabrai.com/docs/standards/drawing-standards/)
- [Modeling Rules](https://cadabrai.com/docs/standards/modeling-rules/)
- [Components and Fasteners](https://cadabrai.com/docs/standards/libraries-and-plm/)

### Account and plans

- [Overview](https://cadabrai.com/docs/account/)
- [Your Account](https://cadabrai.com/docs/account/your-account/)
- [Workstations](https://cadabrai.com/docs/account/workstations/)
- [Plans and Limits](https://cadabrai.com/docs/account/plans-and-limits/)
- [Preferences](https://cadabrai.com/docs/account/preferences/)
- [Billing](https://cadabrai.com/docs/account/billing/)

### Team

- [Overview](https://cadabrai.com/docs/team/)
- [Seats and Members](https://cadabrai.com/docs/team/seats-and-members/)
- [Single Sign-On](https://cadabrai.com/docs/team/sso/)
- [Directory Sync](https://cadabrai.com/docs/team/directory-sync/)

### Security and data

- [Overview](https://cadabrai.com/docs/security/)
- [Data Handling](https://cadabrai.com/docs/security/data-handling/)

### Troubleshooting

- [Overview](https://cadabrai.com/docs/troubleshooting/)
- [CADABRA Issues](https://cadabrai.com/docs/troubleshooting/cadabra-issues/)
- [SOLIDWORKS Errors](https://cadabrai.com/docs/troubleshooting/solidworks-errors/)
- [Error Messages](https://cadabrai.com/docs/troubleshooting/error-messages/)

# Directory sync

SCIM 2.0 behind a bearer token, so a joiner takes a seat and a leaver gives one back with nobody opening the dashboard.

Directory sync is Enterprise, and the card is owner only. An organization is created by CADABRA when the Enterprise agreement is set up. There is no self-serve way to create one, and [the Team page](https://cadabrai.com/docs/team/seats-and-members/#where) is hidden until there is.

## Where it is

The **Directory sync** card sits on the [Team page](https://cadabrai.com/docs/team/seats-and-members/). Off, it reads "Connect Entra or Okta so joiners get a seat and leavers lose one automatically." On, it reads "Directory sync is on. Joiners get a seat and leavers lose one automatically."

It is SCIM 2.0 with a long-lived bearer token. One endpoint serves every provider; nothing in it is Entra or Okta specific.

## Turning it on

1. Generate the token Press Generate token. It confirms with "It is shown once and stored hashed. Any token you generated before stops working immediately, so generate a new one only when you are setting sync up or rotating it."
2. Copy both fields Endpoint and Token appear under the line "Copy the token now. It is stored hashed and cannot be shown again." Only a SHA-256 hash is kept, so a lost token is replaced, never recovered.
3. Paste them into your provider In Entra these are the provisioning Tenant URL and Secret Token; in Okta, the SCIM connector base URL and the HTTP header bearer token. Test Connection reads /ServiceProviderConfig and passes with no further configuration.
4. Assign people Assign the users or the group CADABRA covers, and run a cycle. The Members table and the Activity card show what landed.

The endpoint and the token. Copy the endpoint the dashboard prints rather than typing this.

```
https://accounts.cadabrai.com/scim/v2

Authorization: Bearer <org id>.<43 characters of base64url>
Content-Type: application/scim+json
```

A person must already have a CADABRA account before SCIM can attach them, unless [single sign-on](https://cadabrai.com/docs/team/sso/) is on, in which case their first sign-in creates it. Provisioning an unknown address answers "That person does not have a CADABRA account yet. They need to sign up once, then SCIM will attach and manage their seat."

## What is implemented

Users only. There is no /Groups resource at any path.

| Request | Effect |
| --- | --- |
| `GET /ServiceProviderConfig` | Capabilities. patch true, filter true with maxResults 200, bulk false, sort false, etag false, changePassword false. |
| `GET /ResourceTypes` | One resource type, User. |
| `GET /Users` | Every member of the organization. `startIndex` and `count` paginate; count defaults to 100 and is capped at 200. |
| `GET /Users?filter=` | Only `userName eq "value"` is understood. Anything else is a 400 `invalidFilter`. |
| `GET /Users/{id}` | One member. The id is the CADABRA account id, which is what POST returns. |
| `POST /Users` | Attaches an existing CADABRA account to the organization and consumes a seat. 201 with the user. |
| `PATCH /Users/{id}` | Only `active` is acted on. `active: false` deprovisions. Every other operation is accepted and ignored. |
| `PUT /Users/{id}` | Same rule: `active: false` deprovisions, the rest of the body is ignored. |
| `DELETE /Users/{id}` | Deprovisions. 204, no body. |

The only PATCH that changes anything

```
PATCH /scim/v2/Users/{id}
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [{ "op": "replace", "path": "active", "value": false }]
}
```

## What deprovisioning does

Setting `active` to false, or sending a DELETE, does exactly what **Remove** on the Team page does:

- the account leaves the organization and its seat is freed
- its plan is set to `free`, so Drawings Mode and the organization allowance stop
- any admin flag is cleared
- the [activity log](https://cadabrai.com/docs/team/seats-and-members/#activity) records it with the actor `SCIM`

The account itself is not deleted, and the person keeps it. Deleting an account is theirs to do, from [Your account](https://cadabrai.com/docs/account/your-account/).

With [single sign-on](https://cadabrai.com/docs/team/sso/#first-signin) on, an address at a verified domain that has never signed in through your identity provider is joined to the organization again on its first sign-in there, and takes the seat back. An account that has already signed in that way returns without an organization. Remove a leaver at your identity provider as well, not only in CADABRA.

`active` on a read is not a stored field. It is true when that account is currently a member of the organization asking, and false otherwise.

## What does not sync

- **Groups.** There is no `/Groups` endpoint. Assigning a group in your provider works only insofar as the provider expands it into individual users.
- **Roles.** Admin and owner are set in the dashboard by the owner. No claim, group or SCIM attribute grants either.
- **Names and email addresses.** They are read from the CADABRA account and returned; a write is ignored. Nothing your directory sends renames or re-addresses an account.
- **Passwords.** `changePassword` is false. Credentials stay in your identity provider.
- **Bulk, sort and ETag.** All three report false, so a provider that expects them falls back to per-user calls.
- **Everything except active.** A PATCH or PUT that changes any other attribute succeeds and changes nothing.

## The refusals, and what to do

- **401 "Invalid token."** The token was rotated or revoked. Generate a new one and paste it into your provider.
- **507 "No seats available. Add seats before provisioning more people."** Provisioning stops at the seat cap. [Buy seats](https://cadabrai.com/docs/team/seats-and-members/#seats), then run the cycle again.
- **409 "User already provisioned."** Already a member. Harmless, and providers treat it as a match.
- **409 "That user belongs to another organization."** An account is in one organization at a time.
- **403 "The organization owner cannot be deprovisioned through SCIM."** Deliberate: it stops a directory rule from locking your organization out of itself. Transfer ownership in the dashboard first.
- **404 "User not found."** The id is unknown, or belongs to an account outside your organization.

Every error body is a `urn:ietf:params:scim:api:messages:2.0:Error` carrying `status` and `detail`, and responses are `Content-Type: application/scim+json`.

## Rotating and turning it off

Once sync is on the button reads **Rotate token**. A new token invalidates the previous one the moment it is issued, so paste the replacement into your provider in the same sitting.

**Turn off** confirms with "The token stops working immediately, and your identity provider can no longer add or remove members." Members already provisioned keep their seats; the directory stops driving the list.

Both actions are written to the activity log as "changed the SCIM token", with the detail `issued` or `revoked`.

A provisioning failure that survives a token rotation is worth sending to team@cadabrai.com with the provider name, the request it logged, and the response body. We reply within one business day.

On this page

- [Where it is](#where)
- [Turning it on](#turn-on)
- [What is implemented](#implemented)
- [What deprovisioning does](#deprovision)
- [What does not sync](#not-synced)
- [The refusals, and what to do](#errors)
- [Rotating and turning it off](#rotate)
