Summary and recommendation
8x8 exposes a SCIM 2.0 API at https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2, authenticated via a static Bearer token generated in Admin Console - not an OAuth 2.0 flow. The token does not expire on a schedule but is invalidated if the SCIM toggle is disabled. SSO (SAML) must be configured as a prerequisite before SCIM can be enabled.
Supported operations are GET (list/single user), POST (create), PUT (full replace), PATCH (active field only), and DELETE (deactivates, does not delete). Only one write client is supported at a time; if Azure AD or Okta is the primary IdP, any secondary SCIM client is restricted to GET operations.
Teams building against this API via an MCP server with ~100 deep IT/identity integrations should treat 8x8 as a create-and-deactivate surface, not a full attribute-management surface.
API quick reference
| Has user API | Yes |
| Auth method | Bearer Token (static API token generated from 8x8 Admin Console; not OAuth 2.0) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Any 8x8 X Series subscription (quote-based). SSO must be configured as a prerequisite. |
Authentication
Auth method: Bearer Token (static API token generated from 8x8 Admin Console; not OAuth 2.0)
Setup steps
- Log in to 8x8 Admin Console.
- From Home, navigate to Identity and Security.
- In the User Provisioning Integration (SCIM) section, enable the SCIM toggle.
- Select 'Other SCIM Provider' (or Azure AD / Okta for pre-built integrations).
- Copy the 8x8 URL (SCIM base URL including your CUSTOMER_ID) and the 8x8 API Token.
- Pass the API Token as a Bearer token in the HTTP Authorization header on all SCIM requests.
- Note: If an external IdP (Azure AD or Okta) is already configured, the same token can be reused for GET-only operations by a secondary client.
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| userName | string | The user's login ID / username. Also sets Federation ID on create. | required | read-only after create | Must be unique. Sets Federation ID (used for SSO) on initial create only. |
| name.givenName | string | User's first name. | required | writable | |
| name.familyName | string | User's last name. | required | writable | |
| emails[].value | string | User's email address. Exactly one work email required. | required | writable | Must include exactly one email with type=work and primary=true. |
| active | boolean | Whether the user account is active or deactivated. | optional | writable via PATCH or PUT | Setting active=false deactivates the user; DELETE also results in deactivation, not deletion. |
| externalId | string | External identifier from the IdP. | optional | writable | |
| locale | string | User's locale, e.g. en-US. | optional | writable | |
| timezone | string | User's timezone, e.g. US/Pacific. | optional | writable | |
| title | string | User's job title. | optional | writable | |
| phoneNumbers[].value | string | Phone numbers; type can be 'work' or 'mobile'. | optional | writable | Work phone number cannot be set via SCIM per documented limitations. |
| urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.department | string | User's department (Enterprise SCIM extension). | optional | writable | |
| urn:ietf:params:scim:schemas:extension:8x8:1.1:User.site | string | 8x8 site name the user belongs to (8x8 custom extension). | optional | read-only after set | Cannot be updated once set via SCIM. Must match an existing site name in Admin Console. |
| id | string | 8x8-assigned internal user ID. Returned on GET; used in URL path for single-user operations. | server-generated | read-only | Returned in responses; cannot be set by client. |
Core endpoints
List Users
- Method: GET
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users - Watch out for: Use startIndex (1-based) and count for pagination. If an external IdP is active, a secondary SCIM client may only perform GET operations.
Request example
GET /scim/v2/Users?startIndex=1&count=50
Authorization: Bearer {API_TOKEN}
Response example
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 120,
"startIndex": 1,
"itemsPerPage": 50,
"Resources": [{...}]
}
Get User
- Method: GET
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users/{userId} - Watch out for: The userId in the path is the 8x8-internal id, not the userName or externalId.
Request example
GET /scim/v2/Users/abc123
Authorization: Bearer {API_TOKEN}
Response example
{
"id": "abc123",
"userName": "jdoe",
"name": {"givenName": "John", "familyName": "Doe"},
"active": true,
"emails": [{"value": "john@abc.com", "type": "work", "primary": true}]
}
Create User
- Method: POST
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users - Watch out for: userName, givenName, familyName, and exactly one work email are required. License must be manually assigned in Admin Console after provisioning. New users do not appear in Company Directory automatically.
Request example
POST /scim/v2/Users
Authorization: Bearer {API_TOKEN}
Content-Type: application/json
{
"userName": "jdoe",
"name": {"givenName": "John", "familyName": "Doe"},
"active": true,
"emails": [{"value": "john@abc.com", "type": "work", "primary": true}]
}
Response example
HTTP 201 Created
{
"id": "abc123",
"userName": "jdoe",
"active": true
}
Replace User (full update)
- Method: PUT
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users/{userId} - Watch out for: PUT must include ALL attributes regardless of what is being changed. Omitting an attribute is treated as clearing it to null/empty.
Request example
PUT /scim/v2/Users/abc123
Authorization: Bearer {API_TOKEN}
Content-Type: application/json
{
"userName": "jdoe",
"name": {"givenName": "John", "familyName": "Doe"},
"active": true,
"emails": [{"value": "john@abc.com", "type": "work", "primary": true}],
"title": "Senior Manager"
}
Response example
HTTP 200 OK
{"id": "abc123", "userName": "jdoe", "title": "Senior Manager", "active": true}
Partial Update User (deactivate/activate)
- Method: PATCH
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users/{userId} - Watch out for: PATCH only supports modifying the 'active' field. Modification of any other field via PATCH is not supported; use PUT instead.
Request example
PATCH /scim/v2/Users/abc123
Authorization: Bearer {API_TOKEN}
Content-Type: application/json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{"op": "replace", "value": {"active": false}}]
}
Response example
HTTP 200 OK
{"id": "abc123", "userName": "jdoe", "active": false}
Deactivate User (DELETE)
- Method: DELETE
- URL:
https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2/Users/{userId} - Watch out for: DELETE does NOT delete the user. It deactivates the user (sets active=false). Hard deletion is not supported via SCIM.
Request example
DELETE /scim/v2/Users/abc123
Authorization: Bearer {API_TOKEN}
Response example
HTTP 204 No Content
Rate limits, pagination, and events
- Rate limits: No publicly documented rate limits specific to the SCIM user-management API. The 8x8 Analytics End-to-End Journey API documents 10 requests per 60-second sliding window as a reference for developer APIs generally. SCIM-specific limits are not published.
- Rate-limit headers: No
- Retry-After header: Yes
- Rate-limit notes: When rate limits are exceeded on 8x8 APIs, a 429 status code is returned with a Retry-After header. SCIM-specific rate limit headers are not documented in official sources.
- Pagination method: offset
- Default page size: 0
- Max page size: 0
- Pagination pointer: startIndex and count (SCIM 2.0 standard parameters)
| Plan | Limit | Concurrent |
|---|---|---|
| Analytics APIs (documented example) | 10 requests per 60-second sliding window | 0 |
- Webhooks available: No
- Webhook notes: No webhooks are documented for the 8x8 SCIM user-management API. The 8x8 developer portal references a webhooks management API in the context of CPaaS/Connect (messaging), not for user provisioning or Admin Console events.
- Alternative event strategy: Use polling via GET /Users to detect changes, or rely on IdP-driven sync cycles (Azure AD syncs approximately every 40 minutes; Okta has its own cycle).
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Any 8x8 X Series subscription (quote-based). SSO must be configured as a prerequisite.
Endpoint: https://platform-cloud.8x8.com/udi/customers/{CUSTOMER_ID}/scim/v2
Supported operations: GET /Users (list all users, paginated), GET /Users/{id} (get single user), POST /Users (create user), PUT /Users/{id} (full replace/update), PATCH /Users/{id} (partial update; active field only), DELETE /Users/{id} (deactivates user, does not delete)
Limitations:
- DELETE results in deactivation only; hard deletion is not supported.
- PATCH only supports modifying the 'active' field; all other field updates require PUT.
- PUT must include all attributes; omitted fields are cleared to null.
- License (X Series) assignment must be done manually in Admin Console after provisioning.
- Cannot set cost center, user profile, or work phone number via SCIM.
- Cannot update the 'site' field once it has been set via SCIM.
- Users provisioned via SCIM do not automatically appear in the Company Directory; must be manually enabled in Admin Console.
- Only one active SCIM write client is supported; if an external IdP (Azure/Okta) is configured, a secondary client is limited to GET operations only.
- 8x8 custom schema URN is urn:ietf:params:scim:schemas:extension:8x8:1.1:User.
- SSO (SAML) must be configured before enabling SCIM provisioning.
- On-premise Active Directory is not directly supported; requires Azure AD Connect hybrid setup.
Common scenarios
Three workflows cover the practical API surface. Onboarding: POST to /Users with userName, name.
givenName, name. familyName, and one work email; receive a 201 with the 8x8-internal id; then manually assign a license and enable directory visibility in Admin Console - SCIM cannot do either.
Profile updates (department, title, locale): retrieve the full user object via GET /Users/{id}, modify the target fields, and PUT the complete object back - omitting any attribute clears it to null, so partial PUTs will silently corrupt data.
Deactivation: PATCH /Users/{id} with op:replace on active:false, or send DELETE /Users/{id} - both result in deactivation only; hard deletion is not available via API. Confirm state with a follow-up GET.
Onboard a new employee via SCIM
- Ensure SSO is configured and SCIM is enabled in Admin Console (Identity and Security > User Provisioning Integration).
- POST to /scim/v2/Users with required fields: userName, name.givenName, name.familyName, and one work email. Include optional fields: locale, timezone, title, department, and urn:ietf:params:scim:schemas:extension:8x8:1.1:User.site.
- Receive HTTP 201 with the 8x8-assigned user id.
- Manually assign an X Series license to the new user in Admin Console (SCIM cannot do this).
- Manually enable the user in the Company Directory in Admin Console if directory visibility is required.
Watch out for: Omitting the site field on create is fine, but once set it cannot be changed via SCIM. License assignment and directory visibility are always manual steps.
Deactivate a departing employee
- Identify the user's 8x8 internal id via GET /scim/v2/Users?filter=userName eq "jdoe" or list all users.
- Send PATCH /scim/v2/Users/{id} with Operations: [{op: replace, value: {active: false}}], or send DELETE /scim/v2/Users/{id}.
- Confirm the user's active status is false via GET /scim/v2/Users/{id}.
- The user will immediately lose access to 8x8 Work for Desktop and Mobile.
Watch out for: DELETE does not remove the user record; it only deactivates. If using an IdP like Azure AD or Okta, disabling the user in the IdP triggers deactivation automatically on the next sync cycle (~40 min).
Update user profile attributes (e.g., department, title)
- Retrieve the full current user object via GET /scim/v2/Users/{id}.
- Modify the desired fields in the retrieved object (e.g., update title and department).
- Send a PUT /scim/v2/Users/{id} with the complete modified user object including ALL attributes.
- Confirm changes via GET /scim/v2/Users/{id}.
Watch out for: Do not use PATCH for attribute changes other than 'active' - it is not supported. Always use PUT and always include the full user object to avoid accidentally clearing fields.
Why building this yourself is a trap
The PATCH limitation is the most operationally dangerous constraint: only the active field is supported via PATCH, and this is not enforced with a clear error in all cases - developers expecting standard SCIM PATCH behavior will silently fail to update attributes.
PUT-as-full-replace compounds this: any attribute omitted from the body is treated as a clear, meaning a naive update that fetches and re-PUTs a partial object can wipe existing data.
The site field (8x8 custom extension urn:ietf:params:scim:schemas:extension:8x8:1.1:User.site) is immutable once set via SCIM - there is no API path to correct it; it requires direct Admin Console intervention. License assignment, cost center, work phone number, and profile picture are entirely outside SCIM scope.
Rate limits for the SCIM endpoint are not publicly documented; the only published reference is 10 requests per 60-second window from the Analytics API, which should not be assumed to apply here. Plan for 429 responses with Retry-After headers and implement backoff accordingly.
Automate 8x8 workflows without one-off scripts
Stitchflow builds and maintains identity workflows for your exact setup. We cover every app, including the ones without APIs, and run deterministic trigger-to-report workflows with human approvals where they matter.