External API: User sync via SCIM
UnSpot provides a SCIM 2.0 (System for Cross-domain Identity Management, RFC 7643/7644) API for automated user provisioning. Identity providers such as Microsoft Entra ID or Okta use it out of the box, but you can also call it directly from your own scripts and HR systems. This page is the API reference: every endpoint, its parameters, and ready-to-run examples. For connecting an identity provider step by step, see User sync with Microsoft 360 (Azure AD / Entra ID) SCIM API.
Base URL and authentication
When you enable SCIM in Administration > Access > Integrations > SCIM, UnSpot shows your personal base URL and a secret token:
Base URL: https://<your-company-domain>/api/scim
Token: <64-character secret>Every request must include the token in the Authorization header:
Authorization: Bearer <token>For POST, PUT and PATCH requests the Content-Type: application/scim+json header is required — any other value returns 415 Unsupported Media Type (Content-Type must be application/scim+json).
- 401 Access denied — the header is missing, not in
Bearer <token>format, or the token is wrong. - 400 Token is expired — the token validity period has passed; update it in the SCIM settings.
Resources at a glance
| Resource | Endpoints | What it is for |
|---|---|---|
| Users | GET/POST /Users, GET/PUT/PATCH/DELETE /Users/{id}, POST /Users/{id}/avatar | Create, read, update, deactivate and delete UnSpot accounts |
| Groups | GET/POST /Groups, GET/PUT/PATCH/DELETE /Groups/{id} | Manage UnSpot groups and their membership |
| OrgUnits | PUT /OrgUnits | Replace the whole organizational structure tree |
| Schemas | GET /Schemas | Machine-readable description of all supported attributes |
Pagination
List endpoints (/Users, /Groups) accept count (page size, default 20, maximum 1000) and startIndex (1-based index of the first result). Responses use the standard SCIM ListResponse envelope with totalResults, startIndex and itemsPerPage.
Users
List users — GET /Users
Returns all users of your workspace, including deactivated ones. Use it to audit provisioning or find a user’s UnSpot id.
| Query parameter | Type | Description |
|---|---|---|
count | integer | Page size. Default 20, max 1000. |
startIndex | integer | 1-based index of the first result. |
filter | string | Only the form userName eq "email@example.com" is supported. Any other filter returns 400 Filter syntax error. |
curl -H "Authorization: Bearer $TOKEN" \
"https://acme.unspot.com/api/scim/Users?count=50&startIndex=1"
curl -G -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'filter=userName eq "jane.doe@example.com"' \
https://acme.unspot.com/api/scim/UsersResponse 200:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 128,
"startIndex": 1,
"itemsPerPage": 50,
"Resources": [ { ...user objects, see below... } ]
}Create a user — POST /Users
Creates an account. userName is the user’s email and must be unique. If the email belongs to an archived user, the account is restored instead of created. If the welcome email option is enabled in the SCIM settings, the new user receives an invitation.
| Body attribute | Required | Description |
|---|---|---|
schemas | yes | Must contain urn:ietf:params:scim:schemas:core:2.0:User (plus the Unspot extension URN if you send extension attributes). |
userName | yes | Email address, used for login. |
name.givenName / name.familyName | yes | First and last name. |
externalId | no | Your system’s identifier, up to 36 characters, unique. |
title | no | Job title. |
active | no | Default true. false creates a deactivated account. |
phoneNumbers | no | Array; only the first element with type: "work" is used. |
urn:...:enterprise:2.0:User | no | department and manager.value (manager’s UnSpot id or email). |
urn:...:Unspot:2.0:User | no | role, orgUnit (overrides department), employeeId, numberPass, attendance (0–100). |
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.com/api/scim/Users \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jane.doe@example.com",
"name": { "givenName": "Jane", "familyName": "Doe" },
"title": "Product Manager",
"externalId": "00u1abcd2EFGH3ij4x5",
"active": true
}'Response 201 — the created user:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "5f1c9d2e-...-a1b2",
"userName": "jane.doe@example.com",
"name": { "givenName": "Jane", "familyName": "Doe", "formatted": "Jane Doe" },
"active": true,
"title": "Product Manager",
"externalId": "00u1abcd2EFGH3ij4x5",
"phoneNumbers": [ { "type": "work", "value": "+1 555 0100" } ],
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"department": "Product",
"manager": { "value": "8a2b...-uuid", "displayName": "John Smith" }
},
"urn:ietf:params:scim:schemas:extension:Unspot:2.0:User": {
"role": "user", "orgUnit": "Company/Product", "employeeId": "E-1042", "attendance": 60
},
"meta": { "resourceType": "User", "created": "2026-01-15T09:30:00.000Z", "lastModified": "2026-06-02T11:00:00.000Z" }
}- 409 This userName is already used — an active account with this email already exists.
- 409 This externalId is already used — the externalId is taken.
Get a user — GET /Users/{id}
Returns one user by UnSpot id (UUID). Response 200 — the same user object as above.
curl -H "Authorization: Bearer $TOKEN" \
https://acme.unspot.com/api/scim/Users/5f1c9d2e-...-a1b2Replace a user — PUT /Users/{id}
Full update: send the complete user representation (same body as create). Attributes you omit are cleared. For partial changes prefer PATCH. Response 200 — the updated user.
Update user attributes — PATCH /Users/{id}
Partial update in the standard SCIM PatchOp format. This is what identity providers use to change a single field or deactivate a user.
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.com/api/scim/Users/5f1c9d2e-...-a1b2 \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "title", "value": "Head of Product" },
{ "op": "replace", "path": "active", "value": false }
]
}'Supported path values and operations:
| path | replace | add | remove |
|---|---|---|---|
name.givenName, name.familyName, userName | ✓ | ✓ | |
active | ✓ | ||
externalId, title, phoneNumbers[type eq "work"].value | ✓ | ✓ | ✓ |
urn:...:enterprise:2.0:User:department / :manager | ✓ | ✓ | ✓ |
urn:...:Unspot:2.0:User:orgUnit / :attendance | ✓ | ✓ | ✓ |
urn:...:Unspot:2.0:User:role / :numberPass / :employeeId | ✓ |
- Setting
active: falsedeactivates the user (bookings and access are blocked);truereactivates. Deactivation is ignored for administrators. manageraccepts a UnSpot user id (UUID) or an email.- An unsupported
pathor operation returns 400 with an explanation.
Response 200 — the updated user.
Delete a user — DELETE /Users/{id}
Removes the account from the workspace. Response 204 No Content. To temporarily block a user, use PATCH with active: false instead.
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
https://acme.unspot.com/api/scim/Users/5f1c9d2e-...-a1b2Upload an avatar — POST /Users/{id}/avatar
Sets the user’s profile photo. multipart/form-data with a file field: JPEG or PNG, up to 100 KB. Response 200.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@avatar.png" \
https://acme.unspot.com/api/scim/Users/5f1c9d2e-...-a1b2/avatarGroups
List groups — GET /Groups
Returns workspace groups. Same pagination as /Users. Response 200, ListResponse of group objects:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "9c3d...-uuid",
"displayName": "Product team",
"externalId": "okta-grp-42",
"meta": { "resourceType": "Group", "created": "...", "lastModified": "..." }
}Create a group — POST /Groups
Creates a group, optionally with members (members[].value = user ids). displayName must be unique (max 255 characters). Unknown member id returns 404; duplicate displayName/externalId returns 409. Response 201.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.com/api/scim/Groups \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Product team",
"members": [ { "value": "5f1c9d2e-...-a1b2" } ]
}'Get / replace / patch / delete a group
GET /Groups/{id}— one group, response200.PUT /Groups/{id}— full replace (displayNamerequired,members= array of user ids), response204.PATCH /Groups/{id}— PatchOp; supported paths:displayName(replace),externalId(replace, add),members(add, replace, remove). Response204.DELETE /Groups/{id}— response204.
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.com/api/scim/Groups/9c3d...-uuid \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "add", "path": "members", "value": [ { "value": "5f1c9d2e-...-a1b2" } ] }
]
}'Organizational structure
Replace the org structure — PUT /OrgUnits
Replaces the whole department tree in one call. Each item is a node identified by its full path (levels separated by /, up to 4000 characters), with an optional manager (email) and description (max 255).
curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.com/api/scim/OrgUnits \
-d '{
"items": [
{ "path": "Acme", "manager": "ceo@example.com" },
{ "path": "Acme/Product", "manager": "cpo@example.com", "description": "Product org" },
{ "path": "Acme/Product/Design" }
]
}'Response 200. Users are attached to org units via the orgUnit extension attribute (or department).
Schemas
GET /Schemas
Returns machine-readable definitions of all supported resources and attributes, including the UnSpot extension (urn:ietf:params:scim:schemas:extension:Unspot:2.0:User: role, numberPass, orgUnit, employeeId, attendance, read-only workMode). Useful for IdP connectors that discover attributes automatically.
Errors
Errors are returned as JSON with an explanatory message. Common status codes:
| Code | Meaning | Typical causes |
|---|---|---|
| 400 | Bad request | Invalid schema URN, unsupported filter or PATCH path, expired token, validation errors |
| 401 | Access denied | Missing or invalid Bearer token |
| 404 | Not found | Unknown user/group id, unknown member in members |
| 409 | Conflict | Duplicate userName, externalId or displayName |