Security Group Integration API
Security groups are a flexible authorization framework designed to support complex scenarios across PaySuite services. Organizations use them to build reusable access profiles by combining roles with attribute-based access control (ABAC) rules and organizational scope definitions. Once defined, groups can be assigned to users via API.
Understanding security groups
Scope attributes
Each security group's scope is defined through attributes, or name/value pairs that constrain access to specific organizational dimensions. Supported subject attributes include:
OrgItemsIds: its value corresponds to the ExternalId field of the Organization entity in the Data Foundation.
WorkerCountry: its value corresponds to the WorkCountry field of the Worker entity in the Data Foundation.
WorkerPerformanceEligibility: its value corresponds to the PerformanceEligibility field of the Worker entity in the Data Foundation.
EmploymentHomeCountry: its value corresponds to the HomeCountry field of the Employment entity in the Data Foundation.
EmploymentLegalEntity: its value corresponds to the LegalEntityExternalId field of the Employment entity in the Data Foundation.
EmploymentStatus: its value corresponds to the EmploymentStatus field of the Employment entity in the Data Foundation.
EmploymentCostCenter: its value corresponds to the CostCenterExternalId field of the Employment entity in the Data Foundation.
EmploymentMaterialRiskTaker its value corresponds to the MaterialRiskTaker field of the Employment entity in the Data Foundation.
EmploymentGlobalMobilityFlag: its value corresponds to the GlobalMobilityFlag field of the Employment entity in the Data Foundation.
EmploymentHostCountry: its value corresponds to the HostCountry field of the Employment entity in the Data Foundation.
EmploymentHostCountryLegalEntity: its value corresponds to the HostCountryLegalEntityExternalId field of the Employment entity in the Data Foundation.
EmploymentHostCountryCostCenter: its value corresponds to the HostCountryCostCenterExternalId field of the Employment entity in the Data Foundation.
EmploymentJobLevel: its value corresponds to the JobLevel field of the JobArchitecture entity in the Data Foundation.
EmploymentJobTitle: its value corresponds to the JobTitle field of the JobArchitecture entity in the Data Foundation.
EmploymentJobFamily: its value corresponds to the JobFamily field of the JobArchitecture entity in the Data Foundation.
EmploymentJobCategory: its value corresponds to the JobCategory field of the JobArchitecture entity in the Data Foundation.
EmploymentJobFunction: its value corresponds to the JobFunction field of the JobArchitecture entity in the Data Foundation.
LocalGrade: its value corresponds to the LocalGrade field of the IndividualPayRange entity in the Data Foundation.
GlobalGrade: its value corresponds to the GlobalGrade field of the IndividualPayRange entity in the Data Foundation.
WorkRegion: its value corresponds to the WorkRegion field of the Worker entity in the Data Foundation.
The following are not supported at the security group level: the include/exclude attributes IncludeEmployeeIds, ExcludedEmployeeIds, and ExcludedOrgItemIds, and any custom tenant-defined attributes.
Multi-group assignment
Users can belong to multiple security groups. When they do, their effective authorization is the union of all assigned roles and all resolved scope attributes. For example, a user in Group A (CompensationAdmin role, US scope) and Group B (DataFoundationAdmin role, DE scope) would hold both the CompensationAdmin and DataFoundationAdmin roles, with access across both US and DE.
Contextual role filtering
When a user holds more than one role with different authorization scopes, applications can request authorization in the context of a specific active role. In that case, the authorization engine evaluates only the security groups associated with that role rather than returning the union of all assigned scopes. This ensures the correct population is returned for a given experience.
For instance, a user with both the HRBP role and the compensation advisory role can have each role evaluated independently, so that the HRBP-specific population is returned in the HRBP context and the compensation-specific population in the compensation context.
Relationship to existing authorization
Security groups are backward compatible with existing authorization models. If an individual authorization override (ACL) is configured for a user, it takes precedence over security group evaluation. Organizations using legacy role assignment flows can continue operating without migration and adopt security groups incrementally.
Authentication
The Security Group Integration API uses OAuth 2.0 and is protected by an access token. To obtain your token, call the /connect/token endpoint with your client credentials:
client_id: id of the client for which the token is requested; corresponds to the ClientName or CompanyName.
grant_type: constant value client_credentials.
client_secret: client secret; for more information, contact beqom.
scope: constant value integrationapi.
API endpoints
Retrieving all security groups
To retrieve a list of all security groups, call the following endpoint: GET /integrationapi/v1/auth/security-groups.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"succeeded": true,
"errors": [],
"result": [
{
"id": "0a8b4c27-3e9c-4a7a-a0d6-0f6c2b8fb111",
"name": "SG-HRBP-FR",
"roles": ["HRBP"],
"attributes": [
{ "name": "OrgItemsIds", "values": ["All Company"] },
{ "name": "WorkerCountry", "values": ["FR"] }
]
}
]
}Where:
succeeded: true when the operation was successful.
errors: list of error entries; empty on success.
-
result: array of security groups.
id: the security group's unique identifier.
name: the security group's name.
roles: the roles associated with the security group.
-
attributes: name/value pairs associated with the security group.
name: the attribute name (for example, OrgItemsIds or WorkerCountry).
values: list of allowed values for the attribute.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
500 Internal Server Error means that an unexpected error has occurred in the Integration API or the underlying Security Groups service. Exception details are never included in the response. A non-2xx response from the underlying service also carries an X-Trace-Id header.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Retrieving a security group by ID
To retrieve the information related to a single security group, call the following endpoint: GET /integrationapi/v1/auth/security-groups/{id}.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"succeeded": true,
"errors": [],
"result": {
"id": "0a8b4c27-3e9c-4a7a-a0d6-0f6c2b8fb111",
"name": "SG-HRBP-FR",
"roles": ["HRBP"],
"attributes": [
{ "name": "OrgItemsIds", "values": ["All Company"] },
{ "name": "WorkerCountry", "values": ["FR"] }
]
}
}Where:
succeeded: true when the operation was successful.
errors: list of error entries; empty on success.
-
result: the security group.
id: the security group's unique identifier.
name: the security group's name.
roles: the roles associated with the security group.
-
attributes: name/value pairs associated with the security group.
name: the attribute name.
values: list of allowed values for the attribute.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
404 Not Found means that no security group exists for the supplied {id}. Supplying a value that is not a valid GUID also returns 404. The response carries an X-Trace-Id header.
The response body for this error is as follows:
{
"succeeded": false,
"errors": [
{ "code": "404", "description": "Security group not found." }
]
}-
500 InternalServerError means that an unexpected error has occurred.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Retrieving a security group by name
To retrieve a single security group by its name, call the following endpoint: GET /integrationapi/v1/auth/security-groups/by-name/{name}.
The name path parameter (string, required) is the security group's name. Because the name is embedded directly in the URL, any special characters must be percent-encoded. For example, a space becomes %20, so a group named my group would be called as /security-groups/by-name/my%20group.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"succeeded": true,
"errors": [],
"result": {
"id": "0a8b4c27-3e9c-4a7a-a0d6-0f6c2b8fb111",
"name": "SG-HRBP-FR",
"roles": ["HRBP"],
"attributes": [
{ "name": "OrgItemsIds", "values": ["All Company"] },
{ "name": "WorkerCountry", "values": ["FR"] }
]
}
}Where:
succeeded: true when the operation was successful.
errors: list of error entries; empty on success.
-
result: the security group.
id: the security group's unique identifier.
name: the security group's name.
roles: the roles associated with the security group.
-
attributes: name/value pairs associated with the security group.
name: the attribute name.
values: list of allowed values for the attribute.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
404 NotFound means that no security group exists with the supplied {name}. The response carries an X-Trace-Id header.
The response body for this error is as follows:
{
"succeeded": false,
"errors": [
{ "code": "404", "description": "Security group not found." }
]
}-
500 InternalServerError means that an unexpected error has occurred.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Creating a security group
To create one or more security groups in a single request, call the following endpoint: POST /integrationapi/v1/auth/security-groups.
This is a bulk operation. The request is structured in the form of an items array; you can create several security groups simultaneously by including multiple groups in a single call. Each item is processed independently, so some may succeed while others fail. In that case, the call still returns 200 OK. The outcome of every item is reported individually in the response (see the Where: paragraph below).
The following code snippet illustrates the format of the request body:
{
"items": [
{
"name": "string",
"roles": ["string"],
"attributes": [
{
"name": "string",
"values": ["string"]
}
]
}
]
}Where:
-
items (array, required): the security groups to create. At least one item is required.
name (string, required): the security group's name. The name must be non-empty and unique, as no two security groups can share the same name. There are no restrictions on format or character set.
roles (string[], required): the roles to associate with the security group. At least one role is required.
-
attributes (array, required): name/value pairs to associate with the security group. At least one attribute is required.
name (string, required): the attribute name.
values (string[], required): the allowed values for the attribute.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"items": [
{
"name": "HRBP-EMEA",
"id": "550e8400-e29b-41d4-a716-446655440000",
"roles": ["HRBP", "Reviewer"],
"attributes": [...],
"result": "Success",
"validationErrors": null
},
{
"name": "HRBP-EMEA",
"id": null,
"roles": null,
"attributes": null,
"result": "Failed",
"validationErrors": [
{ "key": "409", "value": "Security group with name 'HRBP-EMEA' already exists." }
]
}
]
}-
items: array of per-item results, with one entry for each item submitted in the request.
name: the security group's name.
id: the created security group's unique identifier; null when the item failed.
roles: the roles associated with the security group; null when the item failed.
-
attributes: name/value pairs associated with the security group; null when the item failed.
name: the attribute name.
values: list of allowed values for the attribute.
result: the outcome for this item (Success or Failed).
-
validationErrors: list of errors describing why the item failed; null on success.
key: the error/status code.
value: human-readable explanation.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
400 Bad Request means that the request body is null, is not a valid JSON, or the items array is missing or empty.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/400",
"title": "Bad Request",
"status": 400,
"detail": "One or more validation errors occurred.",
"errors": [
"The items field is required."
],
"traceId": "0HNFS8BHEQCOL:00000002"
}-
500 Internal Server Error means that an unexpected error has occurred.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Updating a security group
To update an existing security group, call the following endpoint: PUT /integrationapi/v1/auth/security-groups/{id}. The id parameter (GUID, required) corresponds to the unique identifier of the security group to update.
The following code snippet illustrates the format of the request body:
{
"name": "UpdatedSecurityGroup",
"roles": ["HRBP"],
"attributes": [
{ "name": "OrgItemsIds", "values": ["All Company"] }
]
}Where:
name (string, required): the security group's name.
roles (string[], required): the roles to associate with the security group. At least one role is required.
-
attributes (array, required): name/value pairs to associate with the security group. At least one attribute is required.
name (string, required): the attribute name.
values (string[], required): the allowed values for the attribute.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"succeeded": true,
"errors": [],
"result": {
"id": "0a8b4c27-3e9c-4a7a-a0d6-0f6c2b8fb111",
"name": "UpdatedSecurityGroup",
"roles": ["HRBP"],
"attributes": [
{ "name": "OrgItemsIds", "values": ["All Company"] }
]
}
}Where:
succeeded: true when the operation was successful.
errors: list of error entries; empty on success.
-
result: the security group.
id: the security group's unique identifier.
name: the security group's name.
roles: the roles associated with the security group.
-
attributes: name/value pairs associated with the security group.
name: the attribute name.
values: list of allowed values for the attribute.
Post-update behavior
When you update a security group, all users assigned to that group automatically receive the new roles and attributes:
Users are automatically updated, and everyone in the security group gets the new settings.
Permissions may change, as adding or removing roles, or changing attributes, affects user access right away.
Downstream systems and other applications are notified of the role changes.
For example, if security group SG-HRBP-FR has 100 users and you add a new legal entity LE-EMEA-001, all 100 users immediately gain access to that legal entity.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
400 Bad Request means that the request body is missing, is not a valid JSON, or fails validation.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/400",
"title": "Bad Request",
"status": 400,
"detail": "One or more validation errors occurred.",
"errors": [
"The name field is required."
],
"traceId": "0HNFS8BHEQCOL:00000002"
}-
404 Not Found means that no security group exists for the supplied {id}. The response carries an X-Trace-Id header.
The response body for this error is as follows:
{
"succeeded": false,
"errors": [
{ "code": "404", "description": "Security group not found." }
]
}-
409 Conflict means that the new name is already used by another security group.
The response body for this error is as follows:
{
"succeeded": false,
"errors": [
{ "code": "409", "description": "Security group with name 'HRBP-EMEA' already exists." }
]
}-
500 Internal Server Error means that an unexpected error has occurred.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Deleting a security group
To delete an existing security group, call the following endpoint: DELETE /integrationapi/v1/auth/security-groups/{id}. The id parameter corresponds to the unique identifier of the security group to be deleted.
On success, the endpoint returns 200 OK.
The following code snippet illustrates a sample response from the API call:
{
"succeeded": true,
"errors": []
}Where:
succeeded: true when the operation was successful.
errors: list of error entries; empty on success.
Post-delete behavior
When you delete a security group, all users assigned to that group lose the associated roles and attributes:
Users lose their group permissions, including all roles and attributes inherited from that group.
Access is removed immediately, and users without other role assignments may lose all access.
Deletion is permanent and cannot be undone.
For instance, deleting the SG-HRBP-FR group with 500 members instantly revokes the roles and attributes for all 500 users.
Error responses
-
401 Unauthorized means that the bearer token is missing, invalid, or expired, or does not carry the integrationapi scope.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/401",
"title": "Unauthorized",
"status": 401,
"traceId": "00-86161ed2ae20c645c3a46535ee2e538e-3e3d23024e1111cb-01"
}-
404 Not Found means that no security group exists for the supplied {id}. The response carries an X-Trace-Id header.
The response body for this error is as follows:
{
"succeeded": false,
"errors": [
{ "code": "404", "description": "Security group not found." }
]
}-
500 Internal Server Error means that an unexpected error has occurred.
The response body for this error is as follows:
{
"type": "https://httpstatuses.io/500",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-1290264074c29690aea3744e50fbc756-4910628d1b86f94c-01"
}Current limitations
Currently, the following limitations apply to security groups:
Security groups cannot be administered via UI; they are managed through API only.
Custom attributes and custom entities are not supported.
Group-level and worker-level inclusion and exclusion filters are unavailable.