{
  "openapi": "3.0.0",
  "info": {
    "title": "Roam HQ SCIM 2.0 API",
    "description": "System for Cross-domain Identity Management (SCIM) v2 is a standard protocol for automating user provisioning.\nRoam HQ supports SCIM 2.0 to allow enterprise identity providers (IdPs) like Okta to seamlessly create, update, deactivate, and synchronize user accounts in Roam.\n\n**OpenAPI Spec:** [scim.json](https://developer.ro.am/scim.json)\n\n## SCIM Base URL and Authentication\n\nAll SCIM API endpoints are served under the following base URL:\n- **Base URL:** `https://api.ro.am/scim/v2`\n\nAccess to the SCIM API requires an App configured with the following scopes:\n- `user:read`, `user:read.email` - for GET operations\n- `user:write` - for write operations\n\nIn \"Roam Administration > Technical Setup\", click \"Enable SCIM\" to automatically generate an App and retrieve its Bearer token. \nInclude the token in the `Authorization: Bearer <token>` header.\nDiscovery endpoints (`/ServiceProviderConfig`, `/Schemas`, `/ResourceTypes`) do **not** require authentication.\n\n## Supported Endpoints\n\nRoam exposes standard SCIM endpoints for Users (plus discovery endpoints). \nAll endpoints accept and return data in the SCIM 2.0 JSON format (`application/scim+json`).\n\n| Endpoint | Methods |\n|----------|---------|\n| `/ServiceProviderConfig` | `GET` |\n| `/ResourceTypes` | `GET` |\n| `/Schemas`, `/Schemas/{schemaId}` | `GET` |\n| `/Users`, `/Users/{id}` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |\n| `/Groups`, `/Groups/{id}` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |\n\n> **Note:** PATCH is supported with limitations:\n> - **Users**: only `replace` of `active` is supported.\n> - **Groups**: `add`/`remove`/`replace` of `members`, and `replace` of `displayName` are supported.\n\n## User Schema Highlights\n\n- **Required:** Users minimally require a name and email: `userName` (email), `name.givenName`, `name.familyName`, `emails[0].value`\n- **displayName:** Roam constructs the display name from givenName & familyName automatically. Any value you send for displayName will be ignored (no error). \n- **userName:** Must match the primary email address. \n- **Immutable:** Email/userName cannot be changed once created.\n\n  If an email must change (e.g., corporate email change), the current workaround is to archive the old user and create a new user with the new email, or contact Roam support for options. \n\n- **Active:** `active: false` archives a user; `active: true` reactivates.\n- **No Password Sync:** Roam does not use passwords and does not support SCIM password management. The password attribute in SCIM is ignored and will not be returned.\n- **Role Extension:** Custom extension `urn:ro.am:params:scim:schemas:extension:roam:2.0:User.role` accepts `User` or `Admin`, defaulting to \"User\". \n  This role controls access to Roam Administration.\n\n## User Schema Reference\n\nSCIM User Resource – Schema and Behavior\n\nRoam’s SCIM User resource conforms to the SCIM core User schema (urn:ietf:params:scim:schemas:core:2.0:User) with a custom extension for user role. The following attributes are supported or have special behavior in Roam:\n\n- id: (string, read-only) – The unique identifier for the user in Roam. \n  This is Roam’s internal Person ID, returned as a string in SCIM responses. \n  The id is generated by Roam and cannot be changed by the client.\n\n- userName: (string, required) – The username for the account. \n  Roam uses the email address as the userName. \n  When creating a user, the userName field must be the user’s email address, and it must exactly match the primary email value provided. \n  If userName does not match the email, the creation is rejected (\"userName must match primary email\" error). \n  Once a user is created, the userName/email is immutable – any attempt to change a user’s email or userName via SCIM will be rejected with a 400 error (\"email may not be updated\"). \n  (Uniqueness: Roam enforces that no two users in the same account have the same email/userName; creating a user with an email that already exists in your Roam account returns a SCIM uniqueness error 409.)\n\n- name: (complex, required) – The structured name of the user. \n  Roam requires both givenName (first name) and familyName (last name) to be provided in the name object when creating or updating a user.\n  If either is missing, the request is rejected (\"name must contain givenName and familyName\" error).\n  Roam constructs the display name internally from these components. (Middle names or honorifics are not explicitly handled by SCIM in this implementation.)\n\n- displayName: (string) – The full name of the user, typically for display purposes. \n  Roam ignores any displayName value sent in a SCIM request. \n  Instead, Roam will automatically set the display name to “givenName + familyName” (with a space) on the user’s account. \n  In SCIM GET responses, displayName is always populated with the user’s full name as stored in Roam. \n  (Any displayName provided on create/update is accepted but silently ignored.)\n\n- emails: (array of complex) – The email addresses for the user. \n  Roam requires at least one email and uses the first entry as the primary email. \n  You should provide an array with a single object containing the user’s email, e.g. emails: `[{ \"value\": \"alice@company.com\", \"primary\": true, \"type\": \"work\" }]`. \n  The primary email’s value must equal the userName (Roam enforces this). \n  Additional email entries (secondary emails) are ignored in the current implementation – only one email (the primary) is stored. \n  The primary email cannot be changed after creation (immutable, as noted above).\n\n- active: (boolean) – The active status of the user’s account. \n  If omitted on create, Roam assumes active: true (meaning the account is active/enabled). \n  Set active: false to indicate the user should be deactivated in Roam. \n  Deactivation behavior: If active is set to false in a PUT (or if the SCIM Delete operation is called), Roam will mark the user as Archived, which revokes their access but keeps their account record. \n  Setting active: true on an archived user will reactivate (un-archive) them.\n\n- externalId: (string, optional) – An external identifier for the user, typically used to correlate the Roam user with the IdP’s user record. \n  Roam will store this value (if provided) as an external HR system ID for the user. \n  The externalId is returned in GET responses if it was set. \n  Roam does not enforce uniqueness or format on this field; it’s solely for the client’s reference. \n  (When a user is archived or reprovisioned, the externalId remains stored unless overwritten by a subsequent update.)\n\n- password: (string, optional) – Not supported. \n  Roam does not use or sync user passwords via SCIM. \n  If a password attribute is included in a request, it will be ignored. \n  Roam does not return a password attribute in any response. \n\n- Roles (Custom Extension): Roam defines a custom SCIM extension to assign user roles (standard User vs Admin in Roam). \n  The extension URN is: `urn:ro.am:params:scim:schemas:extension:roam:2.0:User`.\n\n  Under this extension, Roam supports a single attribute: role. \n  This is a string indicating the user’s role in Roam, with allowed values \"User\" or \"Admin\". \n  In SCIM responses, each user’s data will include a section like:\n\n  ```json\n      \"urn:ro.am:params:scim:schemas:extension:roam:2.0:User\": {\n          \"role\": \"User\"\n      }\n  ```\n\n  By default, if you do not supply this extension on create, Roam will assign new users the role \"User\" (regular non-admin). \n\n\nApart from the above, Roam’s SCIM user implementation ignores any other standard SCIM user attributes that are not listed. \nAttributes such as middleName, honorificPrefix/Suffix, title, phoneNumbers, department, etc., if sent, will be ignored (and logged as unknown) -- they will not be stored or returned. \nThe SCIM schemas list for a User will include both the core User schema URN and Roam’s extension URN (since the role sub-attribute is always present in responses, even if its value is \"User\" by default).\n\n## Okta Integration Steps (Summary)\n\n1. In Okta, create a **SCIM 2.0 App Integration**.\n2. Set Base URL to `https://api.ro.am/scim/v2`.\n3. Provide a Roam API token with required scopes.\n4. Test connection (Okta hits `/ServiceProviderConfig`).\n5. Enable **Create Users**, **Update Users**, **Deactivate Users**.\n6. Map attributes: The default mappings should work, but these are the ones required: \n    - First Name → `name.givenName`\n    - Last Name → `name.familyName`\n    - Email → `userName` / `emails[primary]`\n7. (Optional) Map a custom attribute to the `role` extension for admin assignment.\n8. Assign users to the app and monitor provisioning logs.\n\n---\n\nBy following the above documentation and guidelines, you should be able to successfully integrate SCIM 2.0 provisioning for your Roam organization. \nThis will automate user management and ensure your Roam user directory stays in sync with your identity provider. \nFor further questions or support, reach out to Roam’s developer support.\n",
    "version": "1.0",
    "termsOfService": "https://ro.am/terms",
    "contact": {
      "name": "Developer Support",
      "email": "developer@ro.am",
      "url": "https://developer.ro.am"
    }
  },
  "servers": [
    {
      "url": "https://api.ro.am/scim/v2",
      "description": "Production Server"
    }
  ],
  "tags": [
    {
      "name": "Users",
      "description": "User provisioning and management"
    },
    {
      "name": "Groups",
      "description": "Group provisioning and management"
    },
    {
      "name": "Metadata",
      "description": "SCIM discovery endpoints"
    }
  ],
  "externalDocs": {
    "description": "SCIM API Documentation",
    "url": "https://developer.ro.am/docs/scim"
  },
  "paths": {
    "/ServiceProviderConfig": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "Get Service Provider Config",
        "description": "Returns Roam's SCIM capabilities and supported features. Use this endpoint to discover which SCIM operations are supported.\n\n**No authentication required** for this discovery endpoint.\n\nSee [RFC 7644 §4](https://www.rfc-editor.org/rfc/rfc7644#section-4) for the SCIM service provider configuration specification.\n",
        "operationId": "03-metadata-service-provider-config",
        "responses": {
          "200": {
            "description": "Service Provider configuration",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceProviderConfig"
                }
              }
            }
          }
        }
      }
    },
    "/ResourceTypes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "Get Resource Types",
        "description": "Returns the list of resource types supported by Roam: `User` and `Group`.\n\n**No authentication required** for this discovery endpoint.\n\nSee [RFC 7644 §4](https://www.rfc-editor.org/rfc/rfc7644#section-4) for the SCIM resource types specification.\n",
        "operationId": "03-metadata-resource-types",
        "responses": {
          "200": {
            "description": "Resource types",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/ResourceTypeList"
                }
              }
            }
          }
        }
      }
    },
    "/Schemas": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "List Schemas",
        "description": "Returns all SCIM schemas supported by Roam, including the core User and Group schemas plus Roam's custom role extension (`urn:ro.am:params:scim:schemas:extension:roam:2.0:User`).\n\n**No authentication required** for this discovery endpoint.\n\nSee [RFC 7644 §4](https://www.rfc-editor.org/rfc/rfc7644#section-4) for the SCIM schemas specification.\n",
        "operationId": "03-metadata-list-schemas",
        "responses": {
          "200": {
            "description": "Schemas list",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/SchemaList"
                }
              }
            }
          }
        }
      }
    },
    "/Schemas/{schemaId}": {
      "parameters": [
        {
          "in": "path",
          "name": "schemaId",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "Get Schema",
        "description": "Returns the definition of a specific SCIM schema by its URN identifier.\n\n**No authentication required** for this discovery endpoint.\n\nCommon schema IDs:\n- `urn:ietf:params:scim:schemas:core:2.0:User`\n- `urn:ietf:params:scim:schemas:core:2.0:Group`\n- `urn:ro.am:params:scim:schemas:extension:roam:2.0:User`\n",
        "operationId": "03-metadata-get-schema",
        "responses": {
          "200": {
            "description": "Schema definition",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/Schema"
                }
              }
            }
          }
        }
      }
    },
    "/Users": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "List Users",
        "description": "Returns a paginated list of users in your Roam organization.\n\n**Filtering:** Supports SCIM filter expressions, e.g., `filter=userName eq \"alice@example.com\"`.\n\n**Pagination:** Use `startIndex` (1-based) and `count` to paginate through results.\n\nSee [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2) for SCIM filtering and pagination.\n",
        "operationId": "01-users-list",
        "parameters": [
          {
            "in": "query",
            "name": "filter",
            "schema": {
              "type": "string"
            },
            "description": "SCIM filter expression"
          },
          {
            "in": "query",
            "name": "startIndex",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "count",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User list response",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Users"
        ],
        "summary": "Create User",
        "description": "Provisions a new user in your Roam organization.\n\n**Required fields:** `userName`, `name.givenName`, `name.familyName`, and `emails[0].value`.\n\n**Roam-specific behavior:**\n- `userName` must exactly match the primary email address\n- `displayName` is auto-generated from givenName + familyName (any provided value is ignored)\n- Email/userName becomes **immutable** after creation\n- Use the `urn:ro.am:params:scim:schemas:extension:roam:2.0:User` extension to set `role` (\"User\" or \"Admin\")\n\nSee [RFC 7644 §3.3](https://www.rfc-editor.org/rfc/rfc7644#section-3.3) for SCIM resource creation.\n",
        "operationId": "01-users-create",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/User"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    },
    "/Users/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get User",
        "description": "Retrieves a single user by their Roam Person ID.\n\nThe response includes all user attributes, the `active` status, and the Roam role extension.\n\nSee [RFC 7644 §3.4.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.1) for SCIM resource retrieval.\n",
        "operationId": "01-users-get",
        "responses": {
          "200": {
            "description": "User object",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Users"
        ],
        "summary": "Replace User",
        "description": "Fully replaces a user's attributes. You must provide all required fields in the request body.\n\n**Roam-specific behavior:**\n- `userName` and `emails` are **immutable** — any attempt to change them returns a 400 error\n- You can update `name.givenName`, `name.familyName`, `active`, `externalId`, and `role`\n- Set `active: false` to archive the user; `active: true` to reactivate\n\nSee [RFC 7644 §3.5.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.1) for SCIM resource replacement.\n",
        "operationId": "01-users-replace",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/User"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Users"
        ],
        "summary": "Delete User",
        "description": "Archives a user in Roam. This is a **soft delete** — the user's data is retained but they lose access.\n\n**Roam-specific behavior:**\n- The user is marked as archived (equivalent to `active: false`)\n- Archived users can be reactivated via PUT or PATCH with `active: true`\n- To permanently delete user data, contact Roam support\n\nSee [RFC 7644 §3.6](https://www.rfc-editor.org/rfc/rfc7644#section-3.6) for SCIM resource deletion.\n",
        "operationId": "01-users-delete",
        "responses": {
          "204": {
            "description": "User archived"
          }
        }
      },
      "patch": {
        "tags": [
          "Users"
        ],
        "summary": "Patch User",
        "description": "Partially updates a user. Roam supports SCIM PATCH for Users with **limited semantics**.\n\n**Supported operations:**\n- `replace` of `active` only (to archive or reactivate a user)\n\n**Not supported:**\n- `add` / `remove` operations\n- `replace` for any other attribute\n\nTo update other fields like name, use PUT (Replace User) instead.\n\nSee [RFC 7644 §3.5.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2) for SCIM PATCH operations.\n",
        "operationId": "01-users-patch",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchOp"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    },
    "/Groups": {
      "get": {
        "tags": [
          "Groups"
        ],
        "summary": "List Groups",
        "description": "Returns a paginated list of groups in your Roam organization.\n\n**Pagination:** Use `startIndex` (1-based) and `count` to paginate through results.\n\n**Note:** The `filter` parameter is accepted but currently ignored for Groups.\n\nSee [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2) for SCIM filtering and pagination.\n",
        "operationId": "02-groups-list",
        "parameters": [
          {
            "in": "query",
            "name": "filter",
            "schema": {
              "type": "string"
            },
            "description": "SCIM filter expression (currently ignored for Groups)"
          },
          {
            "in": "query",
            "name": "startIndex",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "count",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Group list response",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Groups"
        ],
        "summary": "Create Group",
        "description": "Creates a new group in your Roam organization.\n\n**Required fields:** `displayName` (max 64 characters).\n\n**Optional:** Include `members` array with user IDs to add initial members.\n\nSee [RFC 7644 §3.3](https://www.rfc-editor.org/rfc/rfc7644#section-3.3) for SCIM resource creation.\n",
        "operationId": "02-groups-create",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/Group"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Group created",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          }
        }
      }
    },
    "/Groups/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Groups"
        ],
        "summary": "Get Group",
        "description": "Retrieves a single group by its Roam Address ID.\n\nThe response includes the group's `displayName` and `members` array containing user IDs.\n\nSee [RFC 7644 §3.4.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.1) for SCIM resource retrieval.\n",
        "operationId": "02-groups-get",
        "responses": {
          "200": {
            "description": "Group object",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Groups"
        ],
        "summary": "Replace Group",
        "description": "Fully replaces a group's attributes. The entire `members` list is replaced with the provided values.\n\n**Required fields:** `displayName` (max 64 characters).\n\n**Note:** This is a full replacement — any members not included in the request will be removed from the group.\n\nSee [RFC 7644 §3.5.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.1) for SCIM resource replacement.\n",
        "operationId": "02-groups-replace",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/Group"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated group",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Groups"
        ],
        "summary": "Patch Group",
        "description": "Partially updates a group. Use this to add or remove members without replacing the entire group.\n\n**Supported operations:**\n- `add` / `remove` / `replace` for `members`\n- `replace` for `displayName`\n\n**IdP compatibility:**\n- Okta-style: `path: \"members[value eq \\\"user-id\\\"]\"` with `op: \"remove\"`\n- Entra-style: `path: \"members\"` with `value: [{ \"value\": \"user-id\" }]`\n\nSee [RFC 7644 §3.5.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2) for SCIM PATCH operations.\n",
        "operationId": "02-groups-patch",
        "requestBody": {
          "required": true,
          "content": {
            "application/scim+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchOp"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated group",
            "content": {
              "application/scim+json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Groups"
        ],
        "summary": "Delete Group",
        "description": "Archives a group in Roam. This is a **soft delete** — the group data is retained but becomes inactive.\n\n**Roam-specific behavior:**\n- The group is marked as archived\n- Members are removed from the group\n- To permanently delete group data, contact Roam support\n\nSee [RFC 7644 §3.6](https://www.rfc-editor.org/rfc/rfc7644#section-3.6) for SCIM resource deletion.\n",
        "operationId": "02-groups-delete",
        "responses": {
          "204": {
            "description": "Group archived"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ServiceProviderConfig": {
        "type": "object",
        "description": "SCIM service provider capabilities.",
        "properties": {
          "patch": {
            "type": "object",
            "properties": {
              "supported": {
                "type": "boolean",
                "example": true
              }
            }
          },
          "filter": {
            "type": "object",
            "properties": {
              "supported": {
                "type": "boolean",
                "example": true
              },
              "maxResults": {
                "type": "integer",
                "example": 100
              }
            }
          }
        }
      },
      "ResourceType": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "ResourceTypeList": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/ListResponse"
          }
        ]
      },
      "Schema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "SchemaList": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/ListResponse"
          }
        ]
      },
      "User": {
        "type": "object",
        "description": "SCIM User resource with Roam role extension.",
        "required": [
          "userName",
          "name",
          "emails"
        ],
        "properties": {
          "schemas": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "id": {
            "type": "string"
          },
          "userName": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "name": {
            "type": "object",
            "required": [
              "givenName",
              "familyName"
            ],
            "properties": {
              "givenName": {
                "type": "string"
              },
              "familyName": {
                "type": "string"
              }
            }
          },
          "displayName": {
            "type": "string"
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "value"
              ],
              "properties": {
                "value": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "primary": {
                  "type": "boolean"
                }
              }
            }
          },
          "active": {
            "type": "boolean"
          },
          "urn:ro.am:params:scim:schemas:extension:roam:2.0:User": {
            "type": "object",
            "properties": {
              "role": {
                "type": "string",
                "enum": [
                  "User",
                  "Admin"
                ]
              }
            }
          }
        }
      },
      "Group": {
        "type": "object",
        "description": "SCIM Group resource. `members[].value` is a Roam Person ID (string).",
        "required": [
          "displayName"
        ],
        "properties": {
          "schemas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "urn:ietf:params:scim:schemas:core:2.0:Group"
            ]
          },
          "id": {
            "type": "string",
            "description": "Group ID (Roam AddressID)."
          },
          "displayName": {
            "type": "string",
            "description": "Group name (max 64 characters)."
          },
          "members": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string",
                  "description": "Roam Person ID."
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "description": "SCIM metadata (included in responses).",
            "properties": {
              "location": {
                "type": "string"
              },
              "resourceType": {
                "type": "string"
              }
            }
          }
        }
      },
      "PatchOp": {
        "type": "object",
        "description": "SCIM PATCH request wrapper (urn:ietf:params:scim:api:messages:2.0:PatchOp).",
        "required": [
          "schemas",
          "Operations"
        ],
        "properties": {
          "schemas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "urn:ietf:params:scim:api:messages:2.0:PatchOp"
            ]
          },
          "Operations": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "op"
              ],
              "properties": {
                "op": {
                  "type": "string",
                  "description": "Operation name.",
                  "enum": [
                    "add",
                    "remove",
                    "replace"
                  ]
                },
                "path": {
                  "type": "string",
                  "description": "Attribute path (e.g. `active`, `members`, `displayName`, or `members[value eq \"123\"]`)."
                },
                "value": {
                  "description": "Operation value."
                }
              }
            }
          }
        }
      },
      "ListResponse": {
        "type": "object",
        "description": "Standard SCIM list response wrapper.",
        "properties": {
          "schemas": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "totalResults": {
            "type": "integer"
          },
          "startIndex": {
            "type": "integer"
          },
          "itemsPerPage": {
            "type": "integer"
          },
          "Resources": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/User"
                },
                {
                  "$ref": "#/components/schemas/Group"
                }
              ]
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "schemas": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "detail": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      }
    }
  }
}