Integrations

SCIM provisioning

Let your identity provider, such as Microsoft Entra ID or Okta, keep your people and groups in InMyWords in step over SCIM 2.0.

This page is for the IT administrator who connects your identity provider to InMyWords.

It covers the SCIM endpoints and attributes, the rules on people and groups, and the settings for Microsoft Entra ID and Okta.

How it works

InMyWords speaks SCIM 2.0 (RFC 7643 and RFC 7644) for people and groups, so your identity provider can add, change and remove them for you.

  1. Base address. https://app.inmywords.chat/api/integrations/scim/v2/
  2. Every request carries the connection's key. Authorization: Bearer imw_<64 hex characters>
  3. Scopes. Users need users:read to read and users:write to change. Groups need groups:read to read and groups:write to change. Changing a group's members changes people, so it needs users:write as well as groups:write.
  4. Content type. Requests and answers use Content-Type: application/scim+json.
  5. Ids and times. Ids are strings of digits, such as "1842". Times are ISO 8601 in UTC.

Endpoints

MethodPathScope
GET/ServiceProviderConfigany
GET/ResourceTypesany
GET/Schemasany
GET/Usersusers:read
POST/Usersusers:write
GET/Users/{id}users:read
PUT/Users/{id}users:write
PATCH/Users/{id}users:write
DELETE/Users/{id}users:write
GET/Groupsgroups:read
POST/Groupsgroups:write
GET/Groups/{id}groups:read
PUT/Groups/{id}groups:write
PATCH/Groups/{id}groups:write
DELETE/Groups/{id}groups:write

Attributes

SCIM attributeInMyWords
User userNameemail address
User emails[primary eq true].valueemail address
User displayNamename shown on a conversation
User name.formattedname shown on a conversation
User titlejob title
User activefalse when the person is disabled
User externalIdkept for the connection that set it
User groupsthe person's one group, read only
Group displayNamegroup name
Group membersthe people in the group

Adding and removing people

What POST /Users does depends on the address you send.

  1. An address with no account. InMyWords makes the account and emails the person a link to set their own password. The answer is 201.
  2. An address whose account belongs to no organisation. The person is invited. The answer is 201, with active false until they accept.
  3. An address whose account belongs to another organisation. The answer is 409 with scimType uniqueness. So is an address already in your organisation, or already invited to it; find that user with a userName eq filter.

A person invited and not yet accepted is a User with active false, under their account's own id, which does not change when they accept. A group you give them is set when they accept. DELETE withdraws the invitation.

userName cannot be changed. Sending a different address answers 400 with scimType mutability.

Setting active to false disables the person, and they cannot sign in. Setting it to true lets them sign in again.

DELETE /Users/{id} removes the person from your organisation. Their account still exists, and nothing is erased.

A person added this way takes a seat on your organisation's plan like anyone else.

Adding people sends email: an account made gets a link to set a password, and an invited account gets an invitation. A connection may cause 50 such emails an hour. The next answers 429 with Retry-After in seconds, and nothing is made.

curl -X POST https://app.inmywords.chat/api/integrations/scim/v2/Users \
  -H "Authorization: Bearer imw_..." \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
    "userName": "[email protected]",
    "externalId": "a3f1c9e2-5b7d-4e8a-9c1f-2d3e4f5a6b7c",
    "displayName": "Morag Ross",
    "title": "Housing officer",
    "emails": [{"value": "[email protected]", "primary": true}],
    "active": true
  }'
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "1842",
  "externalId": "a3f1c9e2-5b7d-4e8a-9c1f-2d3e4f5a6b7c",
  "userName": "[email protected]",
  "displayName": "Morag Ross",
  "name": {"formatted": "Morag Ross"},
  "title": "Housing officer",
  "emails": [{"value": "[email protected]", "primary": true}],
  "active": true,
  "groups": [],
  "meta": {
    "resourceType": "User",
    "created": "2026-10-03T10:21:44Z",
    "location": "https://app.inmywords.chat/api/integrations/scim/v2/Users/1842"
  }
}

Groups

  1. A new group has no permissions. A group made over SCIM starts empty of permissions. You set them in InMyWords or through the groups endpoints of the REST API.
  2. One group per person. Adding a person who is already in a group to a second group answers 409 with scimType uniqueness, and the detail names the group they are in.
  3. A group that holds cases stays. It cannot be deleted, and the answer is 409.
  4. Deleting a group keeps its people. Its members are left in no group, and their accounts still exist.
  5. Changing members needs both write scopes. Adding, removing or replacing members needs users:write as well as groups:write, and without it the answer is 403. A PUT that carries the members already in the group changes no person, and needs groups:write only.
  6. A member value is a user id. It is a string or a number of digits. Anything else, true included, answers 400 invalidValue.
  7. At most 1000 member values a request. The count runs across all the request's operations, and more answers 400 invalidValue.
curl -X PATCH https://app.inmywords.chat/api/integrations/scim/v2/Groups/57 \
  -H "Authorization: Bearer imw_..." \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    "Operations": [
      {"op": "add", "path": "members", "value": [{"value": "1842"}]}
    ]
  }'
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  "status": "409",
  "scimType": "uniqueness",
  "detail": "This person is already in the group Housing officers. A person is in one group at most."
}

Finding people and groups

Three filters are supported.

FilterExample
userName eq/Users?filter=userName eq "[email protected]"
externalId eq/Users?filter=externalId eq "a3f1c9e2-5b7d-4e8a-9c1f-2d3e4f5a6b7c"
displayName eq/Groups?filter=displayName eq "Housing officers"

Any other filter answers 400 with scimType invalidFilter.

Lists come oldest first, and take startIndex (from 1) and count (default 50, at most 100). GET /Groups and GET /Groups/{id} take excludedAttributes=members.

PATCH

PATCH takes the operations add, replace and remove. They apply to the attributes in the table above, including members on a group.

op is read in any case, and active may be sent as "True" or "False", as Entra ID sends it.

You can remove a member with {"op": "remove", "path": "members", "value": [{"value": "1842"}]}, with {"op": "remove", "value": {"members": [{"value": "1842"}]}}, or with {"op": "remove", "path": "members[value eq \"1842\"]"}. Each removes only the members it names.

A filtered path that names no member of the group answers 400 noTarget. A filtered members path is taken with remove only. With add or replace it answers 400 invalidPath.

An attribute InMyWords does not keep, such as name.givenName or phoneNumbers, is accepted and not kept. Its value must still be a string where the schema says string, and a list or an object answers 400 invalidValue.

A PATCH or PUT is all or nothing. If any operation is refused, none of the request is applied.

curl -X PATCH https://app.inmywords.chat/api/integrations/scim/v2/Users/1842 \
  -H "Authorization: Bearer imw_..." \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    "Operations": [
      {"op": "replace", "path": "active", "value": false}
    ]
  }'

Rules on every change

  1. Some permissions are given by a person. Moving a person into a group that holds manage_users, manage_billing, manage_integrations or manage_groups answers 403. Those permissions are given in InMyWords by a person in your organisation.
  2. Somebody can always manage people. Your organisation always keeps at least one enabled person who can manage people. A change that would leave none answers 409. Two requests that arrive together are taken one after the other, so they cannot both pass this check.
  3. Every change is recorded. Each one is written on your organisation's audit trail under the connection's name.

Not supported

  1. Bulk operations.
  2. Sorting.
  3. ETags.
  4. Password change.

/ServiceProviderConfig says the same.

Setting up Microsoft Entra ID

  1. In Entra ID, open Enterprise applications, then New application, then Create your own application, and choose the option for an application not in the gallery.
  2. Open Provisioning and set Provisioning Mode to Automatic.
  3. Tenant URL: https://app.inmywords.chat/api/integrations/scim/v2/
  4. Secret Token: the connection's key, imw_...
  5. Choose Test Connection.
  6. Under Mappings, keep the attribute mappings in the table below and remove the others.
  7. Assign the users and groups to provision, then start provisioning.
  8. Give each person one group only. A person assigned through two groups is refused for the second.
Entra ID attributeSCIM attribute
userPrincipalName or mailuserName
mailemails[type eq "work"].value
displayNamedisplayName
jobTitletitle
Switch([IsSoftDeleted], , "False", "True", "True", "False")active
objectIdexternalId
Group displayNameGroup displayName
Group membersGroup members

Setting up Okta

  1. In Okta, create an app integration with SCIM provisioning, or add SCIM provisioning to an existing app.
  2. SCIM connector base URL: https://app.inmywords.chat/api/integrations/scim/v2/
  3. Unique identifier field for users: userName
  4. Supported provisioning actions: Push New Users, Push Profile Updates, Push Groups.
  5. Authentication Mode: HTTP Header. Authorization: the connection's key, imw_...
  6. Choose Test Connector Configuration.
  7. Under Provisioning, To App, turn on Create Users, Update User Attributes and Deactivate Users.
  8. Keep the attribute mappings in the table below.
  9. Give each person one group only. A person pushed in two groups is refused for the second.
Okta attributeSCIM attribute
login or emailuserName
emailemails[primary eq true].value
displayNamedisplayName
titletitle
user statusactive
Okta user idexternalId
Group nameGroup displayName
Group membersGroup members

When something goes wrong

Every error comes back as a SCIM error: {"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "...", "scimType": "...", "detail": "..."}.

StatusscimTypeWhen
400invalidFilterThe filter is not one of the three supported.
400invalidValueAn attribute is missing or not valid, a member value is not a user id, or a request carries more than 1000 member values.
400noTargetA filtered members path names no member of the group.
400invalidPathA filtered members path on add or replace.
400mutabilityThe request would change userName.
401There is no key, or the key is not valid.
403Integrations are not on for your organisation, the connection does not hold the scope (members need users:write too), or the change would give a permission a connection may not give.
404There is no such user or group in your organisation.
409uniquenessThe person is already in a group, the address is already here or belongs to another organisation, or the externalId or group name is taken.
409The group holds cases, or the change would leave nobody able to manage people.
429Too many calls this minute, or 50 emails this hour. Wait for Retry-After seconds.