Identity v4.1 Search Guide

The Identity v4.1 Search API is built to enable clients to filter based on user identity attributes. This guide presents a set of detailed examples, advanced functionalities, and limitations of Identity v4.1 Search.

Search is an endpoint that enables callers to retrieve a subset of users matching conditions as parameters.

This section outlines popular use cases and assumes the caller has been authenticated within a company resource via Company JWT. The following examples use all available parameters to demonstrate the functionality of this API.

Authentication (Required)

To use Identity v4.1 APIs, the appropriate scopes must be assigned to the requesting authentication application. Contact your SAP Concur account representative to update your Company JWT scopes to access the identity endpoints. After scopes have been granted to your authentication application, please verify the scopes. If you have questions regarding granting scopes, please contact your SAP Concur account representative.

Search for a User by Email Address

Retrieve the UUID of a User Identity Profile based on email address.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "emails.value eq \"John.Doe@sap.com\"",
  "attributes": [ "emails" ]
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 1,
  "startIndex": 1,
  "itemsPerPage": 1,
  "Resources": [
    {
      "emails": [
        {
          "verified": false,
          "type": "work",
          "value": "john.doe@sap.com",
          "notifications": false
        }
      ],
      "id": "f3a49682-5d15-4ed0-9fa1-d834f87ea16e"
    }
  ]
}

Search for Active User(s) Who Have an Email Address that Ends with Company Domain

Retrieve one or more users who are active and have an email address ending with @sap.com.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "active eq true and emails.value ew \"sap.com\"",
  "attributes": [ "active", "emails" ]
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 2,
  "Resources": [
    {
      "active": true,
      "emails": [
        {
          "verified": false,
          "type": "work",
          "value": "john.doe@sap.com",
          "notifications": false
        }
      ],
      "id": "f3a49682-5d15-4ed0-9fa1-d834f87ea16e"
    },
    {
      "active": true,
      "emails": [
        {
          "verified": true,
          "type": "work",
          "value": "johnny.appleseed@sap.com",
          "notifications": false
        }
      ],
      "id": "58d72127-d0af-44ab-957d-ca7b87499f27"
    }
  ]
}

Search for Active Users(s) Who Have Access to an Entitlement

Retrieve one or more users who are active and contain an “Invoice” entitlement.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "active eq true and entitlements eq \"invoice\"",
  "attributes": [ "active", "entitlements" ]
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 2,
  "Resources": [
    {
      "active": true,
      "entitlements": [
        "Travel",
        "Invoice"
      ],
      "id": "f3a49682-5d15-4ed0-9fa1-d834f87ea16e"
    },
    {
      "active": true,
      "entitlements": [
        "Invoice"
      ],
      "id": "58d72127-d0af-44ab-957d-ca7b87499f27"
    }
  ]
}

Search for User(s) Who Work in Bellevue

Retrieve the UUIDs of users who work in Bellevue.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "addresses[type eq \"work\" and locality eq \"Bellevue\"]",
  "attributes": [ "id" ]
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 5,
  "startIndex": 1,
  "itemsPerPage": 5,
  "Resources": [
    {
      "id": "f3a49682-5d15-4ed0-9fa1-d834f87ea16e"
    },
    {
      "id": "58d72127-d0af-44ab-957d-ca7b87499f27"
    },
    {
      "id": "2a09b1ba-125f-4e4c-a8ef-f48a018583cc"
    },
    {
      "id": "b49497ca-9152-475b-8acf-f57b8e2a796d"
    },
    {
      "id": "1077e0e4-a883-4bd1-9dbb-0a54a58ab344"
    }
  ]
}

Search for Active User(s) that Have Been with the Company for at Least 10 Years

Retrieve user(s) who are currently active and have a start date before 2013.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "active eq true and urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:startDate le 2013-12-31",
  "attributes": [ "active", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:startDate" ]
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 2,
  "Resources": [
    {
      "id": "f3a49682-5d15-4ed0-9fa1-d834f87ea16e",
      "active": true,
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "startDate": "2012-08-01"
      }
    },
    {
      "id": "58d72127-d0af-44ab-957d-ca7b87499f27",
      "active": true,
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "startDate": "2013-01-01"
      }
    }
  ]
}

Search Parameters

This API implements the functionality defined in RFC 7644 § 3.4.3.

Parameter Description Required Value
schemas Validate request against schema object. Yes List of Strings
Schemas
filter Narrow returned users matching expression. No Query String
Filtering
count Number of users to return. No 1 - 1000
Pagination
attributes Return only specified fields. No List of Strings
Example
excludedAttributes Return all other fields than specified. No List of Strings
Example
cursor Enable user to continue to the next page. No Encoded String
Pagination

Schemas

The schemas parameter is required and may not be empty. The required format:

"schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ]

Attributes / ExcludedAttributes

Adding attributes and/or excludedAttributes to a query remove attributes from each user-object in the response. The attributes parameter returns only what is requested while the excludedAttributes parameter returns everything except what is requested.

Attribute Notation

Standard attribute notation, RFC-7644, dictates schema extensions and attributes are delimited by colons, and attributes to sub-attributes delimited by periods. All other attributes remain unchanged.

{urn:schema:extension}:{Attribute}.{Sub-Attribute}

{Attribute}.{Sub-Attribute}

A fully qualified path example:

urn:ietf:params:scim:schemas:core:2.0:User:name.givenName

name.givenName

The correct format of a multiple values, a list of strings, for key attributes:

{
  "schemas": [ "urn:ietf:params:scim:api:messages:2.0:ListResponse" ],
  "attributes": ["id", "meta", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:companyId" ]
}

Request

Parameter attributes will return a subset of attributes for each user with active and id (always) in the user list response. Every attributes must follow attribute-notation.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "attributes": [ "active" ]
}

Response

200 OK
Content-Type: application/json
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse" 
  ],
  "totalResults": 1234,
  "startIndex": 1,
  "itemsPerPage": 100,
  "Resources": [
    {
      "id": "uuid-v4-user-1",
      "active": "true"
    },
    {
      "id": "uuid-v4-user-2",
      "active": "false"
    },
    ...
    {
      "id": "uuid-v4-user-100",
      "active": "true"
    }
  ]
}

Request

Parameter excludedAttributes will return all other default attributes in user list response. Every attribute must follow attribute notation.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "excludedAttributes": [ "localeOverrides", "name.familyNamePrefix", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ]
}

Response

200 OK
Content-Type: application/json
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse" 
  ],
  "totalResults": 1234,
  "startIndex": 1,
  "itemsPerPage": 1,
  "Resources": [
    {
      "addresses": [],
      "timezone": "America/New_York",
      "meta": {
          "resourceType": "User",
          "created": "2021-11-17T22:44:09.000164Z",
          "lastModified": "2021-11-17T22:48:31.000891Z",
          "version": 4,
          "location": "https://us.api.concursolutions.com/profile/identity/v4.1/Users/3df11695-e8bb-40ff-8e98-c85913ab2789"
      },
      "displayName": "John Doe",
      "name": {
          "familyName": "Doe",
          "givenName": "John",
          "honorificSuffix": "VI"
      },
      "phoneNumbers": [],
      "emergencyContacts": null,
      "preferredLanguage": "en-US",
      "title": null,
      "dateOfBirth": null,
      "nickName": null,
      "schemas": [
          "urn:ietf:params:scim:schemas:core:2.0:User",
          "urn:ietf:params:scim:schemas:extension:sap:2.0:User"
      ],
      "externalId": "1234_externalId",
      "active": true,
      "id": "3df11695-e8bb-40ff-8e98-c85913ab2789",
      "emails": [
          {
              "verified": false,
              "type": "work",
              "value": "John11_17_1@sap.com",
              "notifications": true
          }
      ],
      "userName": "John11_17_1@sap.com"
    }
  ]
}

Pagination

By default, a single query will return 100 users. To retrieve more than 100 users for a single query, SCIM defines the count query parameter.

NOTE: The startIndex query parameter is not supported due to the behavior of Deep Pagination.

The upper limit of count is 1,000 users for a single query. To go beyond the first 1,000 users, Identity v4.1 Search returns a nextCursor. When passed on the next query, the cursor may be used to return the next page of matching records for a single, unique query. The token will not be returned on the last-page.

Cursor

The cursor/nextCursor SCIM-Based pagination defines a model used to fetch the subsequent ‘pages’ of resources. cursor is a request query-parameter or within the JSON payload, while nextCursor is expected to be in the response.

Usage

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "count": 100,
  "cursor": "eyJjcmVhdGVkLWlkIjoiMTYxMzc2MTkxNF9hYTA0NzQ1MS04MTBkLTQ5MDMtYWE0OS1lYzhjODZlZjUwNTMiLCJzdGFydEluZGV4IjoxMDF9"
}

Response

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse" 
  ],
  "totalResults": 123456,
  "startIndex": 101,
  "itemsPerPage": 100,
  "Resources": [
    {},
    {},
  ],
  "nextCursor": "eyJjcmVhdGVkLWlkIjoiMTYxMzgwNjU4NF85YjQyNTI1NC04ZDE1LTRjM2QtYmE2ZS03MzZkMmJkMTEzN2IiLCJzdGFydEluZGV4IjoyMDF9"
}

May Not Always Be Returned

When totalResults is equal to itemsPerPage, there will not be a nextCursor in the response.

{
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 2,
  "Resources": [
    {},
    {},
  ]
}

When the caller reaches the last page, there will be no nextCursor in the response

{
  "totalResults": 1000,
  "startIndex": 900,
  "itemsPerPage": 100,
  "Resources": [
    {},
    {},
  ]
}

Filtering

A filter is an expression to return a subset of records matching the predicate. Filters are comprised of Attribute Operators, Logical Operators, and Grouping Operators. Examples are listed below.

Parameter Description
Allowed Attributes Term, the subject, eligible for filtering.
Attribute Operators Action, a verb, on comparator, a value.
Logical Operators Multiple expressions are conjoined by logical operators.
Grouping Operators Filtering for sub-attributes. May be used with single-valued or multi-valued attributes.

Allowed Attributes

Attribute Sub-Attributes Data Type
active - boolean
addresses country string
  locality string
  region string
  type string
emails value string
  type string
  verified boolean
entitlements - string
externalId - string
id - string
meta created data
  lastModified date
name familyName string
  givenName string
nickName - string
userName - string
urn:ietf:params:scim:schemas:extension:
enterprise:2.0:User
costCenter string
  department string
  division string
  employeeNumber string
  startDate date
  terminationDate date
urn:ietf:params:scim:schemas:extension:
enterprise:2.0:User:manager
employeeNumber string
  value string
urn:ietf:params:scim:schemas:extension:
sap:2.0:User
userUuid string

Attribute Operators

Conditional relationship between attribute and value stored in database. Multiple operators can be used with zero or more logical operators.

Operator Description Example
eq equal active eq true
ne not equal name.familyName ne "Smith"
co contains name.givenName co "John"
sw starts with name.givenName sw "J"
ew ends with name.givenName ew "n"
pr present (has value) name.givenName pr
gt greater than meta.lastModified gt "2011-05-13T04:42:34Z"
ge greater than or equal to meta.lastModified ge "2011-05-13T04:42:34Z"
lt less than meta.lastModified lt "2011-05-13T04:42:34Z"
le less than or equal to meta.lastModified le "2011-05-13T04:42:34Z"

Logical Operators

Separate attribute expressions. Filters can include zero or more logical operators. By default, logical operators are evaluated in the following order of operations: NOT > AND > OR

This definition may be overwritten by grouping operators.

Operator Description Example
not Match, if expression evaluates to false. not(name.givenName eq "John")
and Match, if both expressions evaluate to true. name.givenName eq "John" and name.familyName eq "Smith"
or Match, if either expression evaluates to true. name.givenName eq "John" or name.givenName eq "James"

Grouping Operators

Evaluate an expression in explicit order.

Operator Description Example
() Precedence grouping, (evaluate first) and overrides precedence. (name.givenName eq "John" or name.givenName eq "James") and name.familyName eq "Smith"
[] Complex attribute filtering, used with multi-valued attributes. emails[type eq "work" and value co "@example.com"

Precedence Examples

The definition provided states: NOT > AND > OR

For the examples below, capital letters (A, B, C) represent different attribute expressions.

Expression Default Evaluation
A or B and C A or (B and C)
A and B or C (A and B) or C
A and B or C and D (A and B) or (C and D)
A or B and C or D A or (B and C) or D
not A or B and C (not A) or (B and C)

Filtering Examples

The filter parameter implemented all the functionality described in Filtering as a string. This section contributes a set of more detailed examples, limitations, and variations of expressions.

Filter is Optional

Company JWT contains companyId, and used to retrieve all users within Company.

Request

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "attributes": [ "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:companyId" ]
}

Response

200 OK
Content-Type: application/json
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 3,
  "startIndex": 1,
  "itemsPerPage": 3,
  "Resources": [
    {
      "id": "ac2527c5-14c8-433e-8394-6894ec11462c",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "companyId": "6eed4eb2-95bb-4edf-86aa-36aec1263321"
      }
    },
    {
      "id": "4f341a2b-6a0a-4ace-b9cd-4a9a0c96e789",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "companyId": "6eed4eb2-95bb-4edf-86aa-36aec1263321"
      }
    },
    {
      "id": "8bce6823-6858-4c92-a019-f1900299c59f",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "companyId": "6eed4eb2-95bb-4edf-86aa-36aec1263321"
      }
    },
  ]
}

Filter By UUID

UUIDs may optionally include the \" quotes.

Request

POST https://us.api.concursolutions.com/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
    "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
    "filter": "id eq c7e128ed-a8a6-4627-bd5d-42f7f89cdeb4"
}

OR

{
    "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
    "filter": "id eq \"c7e128ed-a8a6-4627-bd5d-42f7f89cdeb4\""
}

Both of these payloads are valid and will return the same user profile.

Response

200 OK
Content-Type: application/json
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse"
  ],
  "totalResults": 1,
  "startIndex": 1,
  "itemsPerPage": 1,
  "Resources": [
    {
      "id": "c7e128ed-a8a6-4627-bd5d-42f7f89cdeb4"
    }
  ]
}

Filter By Multi-Valued Attributes

emails and addresses are multi-valued attributes.

Applying a Complex Grouping within a filter will match one and only one record to the condition. Filters that use multi-valued, complex groupings support the following comparison operators: eq / sw / ew / co / pr

Request

POST https://us.api.concursolutions.com/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "emails[type eq \"work\" and value ew \"@example.com\"]"
}

Response

200 OK
Content-Type: application/json
{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:ListResponse" 
  ],
  "totalResults": 1000,
  "startIndex": 1,
  "itemsPerPage": 100,
  "Resources": [
    {
      "id": "user-id-match-1",
      "emails": [
        {
          "verified": true,
          "type": "work",
          "value": "John@example.com",
          "notifications": true
        }
      ]
    },
    {
      "id": "user-id-match-2",
      "emails": [
        {
          "verified": true,
          "type": "work",
          "value": "Appleseed@example.com",
          "notifications": true
        }
      ]
    }
  ]
}

Limitations

Filters may not contain not and ne within Complex Groupings.

"filter": "emails[not(type eq \"work\")]"
"filter": "addresses[type ne \"work\"]"

Filters may not nest or inside parentheses within Complex Groupings.

"filter": "emails[value ew \"@sap.com\" and (type eq \"home\" or type eq \"work\")]"

Duplicate attributes may not be conjoined with and inside of Complex Grouping.

"filter": "emails[value ew \"@concur.com\" and value ew \"@sap.com\"]"
"filter": "emails[value sw \"C\" and value ew \"S\"]"

Complex Grouping: AND

Multi-valued, complex grouping with logical ‘and’ operators cannot conjoin duplicate attributes, or fields, as the intention of this query is to return one and only one match across many users.

Returns users who have a work emails equal to admin@SAP.com.

"filter": "emails[type eq \"work\" and value eq \"admin@SAP.com\"]"

Returns users who work at Concur, as an entry in address.

"filter": "addresses[type eq \"work\" and locality eq \"Bellevue\" and region eq \"WA\"]"

Complex Grouping: OR

Multi-valued, complex grouping with logical ‘or’ operators can only be present at the root-level and cannot be nested within parentheses. The intention of this query is to return one or more matches within a set of records, within a single user, across many users.

Note: Results may include users with all three attributes in a single entry.

Return users with work emails, have admin in their email, or have not verified their email.

"filter": "emails[type eq \"work\" or value sw \"admin\" or verified eq false]"

Return users with work or home addresses in user object.

"filter": "addresses[type eq \"work\" or type eq \"home\"]"

Combined Logical Queries

Returns users that either have work emails that end with @SAP.com or have home emails that end with .com.

"filter": "emails[type eq \"work\" and value ew \"@SAP.com\" or type eq \"home\" and value ew \".com\"]"

Filter Across Values

Multi-valued attributes may also be queried like single-valued attributes. The key difference is that for every and condition, every entry in the list must satisfy the condition.

Return users who have multiple emails that must either end with @concur.com and @sap.com.

"filter": "emails.value ew \"@concur.com\" and emails.value ew \"@sap.com\""

Return users who have a home and work address in their user profile.

"filter": "addresses.type eq \"home\" and addresses.type eq \"work\""

Filter By Name Field

Single-valued attributes with sub-attributes MAY also be grouped with Complex Grouping. Limitations only apply to Complex Grouping of multi-valued attributes, single-valued attributes support all operators.

POST https://us.api.concursolutions.com/profile/identity/v4.1/Users/.search
Accept: application/json
Authorization: BEARER {token}
{
  "schemas": [ "urn:ietf:params:scim:api:messages:concur:2.0:SearchRequest" ],
  "filter": "name.givenName eq \"John\"",
  "count": 100
}

Logical AND Queries

Return users by Full Name (combination of given and family).

"filter": "name.givenName eq \"John\" and name.familyName eq \"Smith\"",
"filter": "name[givenName eq \"John\" and familyName eq \"Smith\"]"

Return users who have the first name John and do not have last name Bob.

Note: When using ne, results can include null values.

"filter": "name.givenName ne \"John\" and not(name.givenName eq \"Bob\")",
"filter": "name[givenName ne \"John\" and not(givenName eq \"Bob\")]"

Return users who must start with and ending with characters, case insensitive.

"filter": "name.givenName sw \"J\" and name.givenName ew \"n\"",
"filter": "name[givenName sw \"J\" and givenName ew \"n\"]"

Return users by “contains” query and check if field, name.givenName has a value.

"filter": "not(name.givenName co \"admin\") and name.givenName pr",
"filter": "name[not(givenName co \"admin\") and givenName pr]"

Combined Logical Queries

"filter": "name.givenName eq \"John\" and name.familyName eq \"Smith\" or name.givenName eq \"Bob\" and name.familyName eq \"Joe\"",
"filter": "name[givenName eq \"John\" and familyName eq \"Smith\"] or name[givenName eq \"Bob\" and familyName eq \"Joe\"]"

On this page