Share This:

There are times when you need to be able to access DWP-C functionality through an API. This might be in order to offer a Business to Business (B2B) interface to external systems, to help automate deployments through a tool like Jenkins or some other automation support. They are many opportunities that an API can open and this post explains how to use the REST API made available for DWP-C and provides an example for one use case.

The first starting point should be the API documentation - See this page for the 20.02 documentation: Integrating BMC Digital Workplace Catalog REST API with the service catalog - Documentation for BMC Digital Workplace Ad…

Since the DWP frontend also uses an extended version of this API, it is well utilised and tested. The usage is relatively simple,  but there are a number of areas that you need to consider.

Authentication

The REST API login uses simple credentials that then generate a token that is valid for 30 minutes. The syntax is shown in the use case below, but you should be aware of the following:

  • In theory, you can submit an RSSO request to get an authentication token for DWP-C, but the RSSO REST API is not public. Therefore it Is easier to have a local account defined in DWP-C. It is recommended that you have a special interface user for this purpose.
  • This user must have a password directly configured for the user in DWP-C and should have the minimum permissions that are required to perform the actions needed in the API. This is particularly true if you are providing API access to external systems, so also think about restricting access via entitlements or other mechanisms. On Helix environments, you will need to raise a ticket with Helix Ops to get the password set for the local DWP-C user.
  • The ITSM user and password will also need to match those on DWP-C if you plan to execute ITSM requests.
  • If you are providing API access to multiple external systems, each of those systems should be given a separate interface user to ensure traceability and that the access for each system can be managed independently.
  • You can set both the requested by (at least from 19.11) and requested for users via the API, so this interface user will not be visible in any requests.
The authorisation uses a simple authentication via a POST request and returns a time-limited token that must then be provided in the header of subsequent requests.
Note that there is currently a constraint here that the bulk request update (POST api/myit-sb/requests) requires DWP-C admin rights.

General Considerations

In general the API is easy to use, but these points should help make it even easier:
  • Make sure that you use UTF-8 character content encoding on all requests unless explicitly told to use something different. We had some issues with JMeter not always setting this and special characters will break otherwise. Note that I have not tried using 16-bit character sets via the API, but if anyone does have any experience of this, please add it to the comments below!
  • If you want to work with the REST API, then you will need some tools to help you. There are a few choices here:
    • A good text editor that understands JSON. There are plenty of text editors that can handle this. Popular examples are Notepad++ and Sublime Text, or BBEdit for the Mac. Make sure you have the relevant JSON plugins.
    • Various Browser plugins that provide REST client functions for testing. These are fine for simple baseline tests, but you will soon want to switch to a more advanced tool such as one of the ones listed below.
    • Postman: A popular REST test client. It has a free version, but more advanced features require payment.
    • JMeter: Part of the Apache project, this is a very powerful and flexible test tool for testing REST interfaces and also other areas. It is public domain and so has the usual advantages and disadvantages (not the easiest to use, but very flexible and free). It is my current tool of choice as it can also easily be used for both functional and load tests.
    • JSON parsing tools: These are generally useful for DWP-C workflows, but particularly so when handling the JSON responses to the REST calls. There are plenty of online JPATH tools that you can easily find, https://jsonpath.com/ is one example.
    • There are other tools that you may also choose. Please add them in the comments so that others can benefit!

REST Headers

REST APIs make use of headers in the requests to provide standard information:

default-bundle-scopemyit-sb
X-Requested-By<Name for source application>
Authorization<The authorisation token from the login request>
content-typeapplication/json

 

Any service requests should also include the following header (only for 19.11 onwards) to ensure that the on behalf of user is set correctly, both within DWP-C requests and any subsequent Work Orders or Incidents in ITSM:

impersonated-user-id<On Behalf of User>

Note that the on behalf of (or requested by) user must include the login name and the DWP-C tenant, e.g. interface_user@bmc.com.

 

Using the API

You should now have the basic information for calling the API, but we will use a specific example to show this in more detail. Note that elements in the example shown in angled brackets and highlighted red should be replaced by appropriate values from your environment and use case. The URL shown also clearly needs to be replaced.

This is one particular use case, if you are interested in others, please add them to the comments.

 

Sample Use Case - Request a Service

A common uses case is an API request to find and submit a specific service request. In order to do this, you need to perform the following steps:

  1. Login
  2. Find the Service Request that you want to call
  3. Populate the answers to the questions
  4. Submit the Request

In detail, this works as follows:

Login

The login step is needed to provide the authorisation token for subsequent requests.

Sample Login Request

POST http://dwpc.bmcdev.localdomain:8008/api/myit-sb/users/login
Headers:
Content-Type: application/json
default-bundle-scope: myit-sb
X-Requested-By: <source application>
Data:
{ "id": "interface_user@bmc.com", "password": "password" }

 

Sample Login Response
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBQXR1ZXFSY0JUcVJQZVZQSk84eFwvSDVrMmlaeVpoU25ycU1NS28ydGt3dDlUTXBLS0JOYlB6TWV5Q0c0Nk91V2FHeUttQ1ZqV3VvRDc1S1FkVkUwXC92dmZma0d5dmJJT3pxMStXbmdCMVB1cFhYZnNGTVNVaEE9PSIsIm5iZiI6MTU4MzYxMzI1NSwiaXNzIjoidHNpLW15aXRzYi5ibWNkZXYubG9jYWxkb21haW4iLCJfYXV0aFN0cmluZyI6IjFCVVh6UWJYcklNMWs2WVwvekRwMkJNbHJsSFQ1REFRRmZ6UTN4U0tHeUo4MkNLMk1lRlNseEdWbmJHenpxT2lnaE1UbHBGXC93N0o0WmY4UFp3bDBqQmxHakZ6VHNFZ0JYQkFTTnBYNHU3TXhYUk1oWE5WYUVlUT09IiwiZXhwIjoxNTgzNjE2OTc1LCJfY2FjaGVJZCI6MTQ2ODI5LCJpYXQiOjE1ODM2MTMzNzUsImp0aSI6IklER0FBNVYwRkU4WTNBUUdVMVc1UUZXNFFFNkpGUSIsIl9hYnNvbHV0ZUV4cGlyYXRpb25UaW1lIjoxNTgzNjk5Nzc1fQ.eBO42c2QTdqDZSxJEGQIScM1lVMzZ8ST9_MdRqa4rWY
Note that the authorisation token is also provided as a header response cookie called AR-JWT.

Search for Service

To search for a service, the recommended approach is to use a GET request that uses FTS. Note that because of the FTS usage, the search string will be tokenised by default, unless you encapsulate the entire string in URL encoded double-quotes ("), i.e. %22. For example %22ITSM%20Demo%22 for "ITSM Demo"
See this page for more details on how search works: How search works in BMC Digital Workplace

 

Sample GET Search Request

GET http://dwpc.bmcdev.localdomain:8008/api/myit-sb/services/search?q=<encoded search string>

Headers:

Content-Type: application/json

default-bundle-scope: myit-sb

X-Requested-By: <source application>
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBQXR1ZXFSY0JUcVJQZVZQSk84eFwvSDVrMmlaeVpoU25ycU1NS28ydGt3dDlUTXBLS0JOYlB6TWV5Q0c0Nk91V2FHeUttQ1ZqV3VvRDc1S1FkVkUwXC92dmZma0d5dmJJT3pxMStXbmdCMVB1cFhYZnNGTVNVaEE9PSIsIm5iZiI6MTU4MzYxMzI1NSwiaXNzIjoidHNpLW15aXRzYi5ibWNkZXYubG9jYWxkb21haW4iLCJfYXV0aFN0cmluZyI6IjFCVVh6UWJYcklNMWs2WVwvekRwMkJNbHJsSFQ1REFRRmZ6UTN4U0tHeUo4MkNLMk1lRlNseEdWbmJHenpxT2lnaE1UbHBGXC93N0o0WmY4UFp3bDBqQmxHakZ6VHNFZ0JYQkFTTnBYNHU3TXhYUk1oWE5WYUVlUT09IiwiZXhwIjoxNTgzNjE2OTc1LCJfY2FjaGVJZCI6MTQ2ODI5LCJpYXQiOjE1ODM2MTMzNzUsImp0aSI6IklER0FBNVYwRkU4WTNBUUdVMVc1UUZXNFFFNkpGUSIsIl9hYnNvbHV0ZUV4cGlyYXRpb25UaW1lIjoxNTgzNjk5Nzc1fQ.eBO42c2QTdqDZSxJEGQIScM1lVMzZ8ST9_MdRqa4rWY

Sample GET Search Response

{

    "page": 1,

    "pageSize": 1,

    "services": [

        {

            "autoDependent": false,

            "available": true,

            "bulkRequestedForUserLimit": 1,

            "bundledServices": [],

            "calculatedAvailability": true,

            "categories": [],

            "createdDate": "2020-02-24T14:39:38.000+0000",

            "description": "<p>Demo Service:</p>\n<p>Requires a Work Order Template</p>",

            "entitled": false,

            "excerpt": "This service contains some example ITSM functions",

            "externalWorkflow": "OTHER",

            "fulfillmentType": "INTERNAL_WORKFLOW",

            "guid": "AGGAA5V0FE8Y3AQERV1GQDUCVOR9X9",

            "iconUrl": "/api/myit-sb/content/AGGAA5V0FE8Y3AQGHN4DQFJQ2CY18A",

            "id": "12603",

            "importedFromITSM": false,

            "isDependent": false,

            "modified": true,

            "modifiedDate": "2020-02-24T14:39:40.000+0000",

            "monthlyCost": 0.0,

            "multiRequestBundle": false,

            "name": "ITSM Demo Service 0.1",

            "onceCost": 0.0,

            "price": {

                "currency": "USD",

                "freeLabelText": "Free",

                "paymentType": "FREE"

            },

            "quantity": {

                "enabled": false,

                "max": 100,

                "min": 1

            },

            "quickRequest": false,

            "rating": 0,

            "ratingCount": 0,

            "reopenWorkflowEditEnabled": false,

            "restrictedFullCatalogView": false,

            "score": 100,

            "serviceType": "IT Request",

            "surveyEnabled": true,

            "templateType": "SERVICE",

            "translations": [],

            "unavailableRequiredServicesCount": 0,

            "useBundledServicesCosts": false,

            "version": "0.1",

            "yearlyCost": 0.0

        }

    ],

    "total": -1

}

The main entry required is the service id (JPATH: $.services[0].id).

 

Add Request with Answers

Questions are defined by a unique ID (in very early versions, this was a sequential id, but now it is a GUID). If you have a fairly static catalogue, you can read the question ids in advance and then simply populate the answers directly.

If you have a more dynamic catalogues that changes more frequently, then you also need to lookup the questions and their IDs. See below for an example of this. There was an older mechanism that required you to submit the answers to each question as individual API calls, but since about 18.08 the recommended approach is to submit all answers in one request and this is the example shown here. The question ids and answers will depend on how they are defined in the catalogue - see also the "Get Questionnaire Details" request below.

Sample Add Request with Answers with
POST http://dwpc.bmcdev.localdomain:8008/api/myit-sb/requests

Headers:

Content-Type: application/json

default-bundle-scope: myit-sb

X-Requested-By: <source application>
impersonated-user-id: <requested by login id@tenant name>

Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBQXR1ZXFSY0JUcVJQZVZQSk84eFwvSDVrMmlaeVpoU25ycU1NS28ydGt3dDlUTXBLS0JOYlB6TWV5Q0c0Nk91V2FHeUttQ1ZqV3VvRDc1S1FkVkUwXC92dmZma0d5dmJJT3pxMStXbmdCMVB1cFhYZnNGTVNVaEE9PSIsIm5iZiI6MTU4MzYxMzI1NSwiaXNzIjoidHNpLW15aXRzYi5ibWNkZXYubG9jYWxkb21haW4iLCJfYXV0aFN0cmluZyI6IjFCVVh6UWJYcklNMWs2WVwvekRwMkJNbHJsSFQ1REFRRmZ6UTN4U0tHeUo4MkNLMk1lRlNseEdWbmJHenpxT2lnaE1UbHBGXC93N0o0WmY4UFp3bDBqQmxHakZ6VHNFZ0JYQkFTTnBYNHU3TXhYUk1oWE5WYUVlUT09IiwiZXhwIjoxNTgzNjE2OTc1LCJfY2FjaGVJZCI6MTQ2ODI5LCJpYXQiOjE1ODM2MTMzNzUsImp0aSI6IklER0FBNVYwRkU4WTNBUUdVMVc1UUZXNFFFNkpGUSIsIl9hYnNvbHV0ZUV4cGlyYXRpb25UaW1lIjoxNTgzNjk5Nzc1fQ.eBO42c2QTdqDZSxJEGQIScM1lVMzZ8ST9_MdRqa4rWY

 

data:
{
"serviceId" : "<service id from service search>",
"requestForUserIds" : ["<requested for login id>"],
"excludedServiceIds": [
],
"quantity" : 1,
"questions": [
{
"questionId": "208859ba-a5d2-51f2-e6ea-2819cce66ded",
"answers": ["Incident"]
},
{
"questionId":"6281d8fe-9058-97ca-04b4-0f48a47e608b",
"answers":["Test Incident via API"]
},
{
"questionId":"1831048b-6303-5135-f9c5-26ece02a3836",
"answers":["Messaging Issue"]
},
{
"questionId":"9266062d-e4ed-0a86-c1d7-ee86e282529a",
"answers":["AGGAA5V0FE8Y3AQGWFEXQFYHYM7I17","AGGAA5V0FE8Y3AQGWFEXQFYHYM7I19"]
}
]
}

Sample Add Request Response

{
   "bundleRequestId": null,
   "guid": "AGGAA5V0FE8Y3AQERV1GQDUCVOR9X9",
   "requestErrors": [],
   "requests": [
   {
   "dependencies": null,
   "externalId": null,
   "onStartChanges": {},
   "questionnaire": null,
   "requestId": "33529",
   "serviceId": "12603"
   }
   ],
   "serviceId": "12603"
}

Get Questionnaire Details

This request can either be used in advance to get the question ids or dynamically as part of the API to get the questions. Here using tags to define question ids may make it easier to lookup the questions in a dynamic, catalogue-driven environment.

Get Questionnaire Details Request
GET http://dwpc.bmcdev.localdomain:8008/api/myit-sb/requests/<request id>/questionnaire

Headers:

Content-Type: application/json

default-bundle-scope: myit-sb

X-Requested-By: <source application>
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBQXR1ZXFSY0JUcVJQZVZQSk84eFwvSDVrMmlaeVpoU25ycU1NS28ydGt3dDlUTXBLS0JOYlB6TWV5Q0c0Nk91V2FHeUttQ1ZqV3VvRDc1S1FkVkUwXC92dmZma0d5dmJJT3pxMStXbmdCMVB1cFhYZnNGTVNVaEE9PSIsIm5iZiI6MTU4MzYxMzI1NSwiaXNzIjoidHNpLW15aXRzYi5ibWNkZXYubG9jYWxkb21haW4iLCJfYXV0aFN0cmluZyI6IjFCVVh6UWJYcklNMWs2WVwvekRwMkJNbHJsSFQ1REFRRmZ6UTN4U0tHeUo4MkNLMk1lRlNseEdWbmJHenpxT2lnaE1UbHBGXC93N0o0WmY4UFp3bDBqQmxHakZ6VHNFZ0JYQkFTTnBYNHU3TXhYUk1oWE5WYUVlUT09IiwiZXhwIjoxNTgzNjE2OTc1LCJfY2FjaGVJZCI6MTQ2ODI5LCJpYXQiOjE1ODM2MTMzNzUsImp0aSI6IklER0FBNVYwRkU4WTNBUUdVMVc1UUZXNFFFNkpGUSIsIl9hYnNvbHV0ZUV4cGlyYXRpb25UaW1lIjoxNTgzNjk5Nzc1fQ.eBO42c2QTdqDZSxJEGQIScM1lVMzZ8ST9_MdRqa4rWY

 

Get Questionnaire Details Response

 

 

{
   "questionnaire": {
   "bulkRequestedForUserLimit": 1,
   "createDate": null,
   "guid": null,
   "id": "12734",
   "modifiedDate": null,
   "name": null,
   "pages": [
   {
   "externalId": null,
   "id": "fa245f88-dc92-8e22-35b2-8fdf2a066234",
   "pageItems": [
   {
   "answerSource": "DEFAULT",
   "confidential": false,
   "defaultAnswer": null,
   "description": null,
   "enabledPasswordEncryption": false,
   "externalId": null,
   "hidden": false,
   "id": "3bf9b9c8-558b-22f4-6ca9-bbb0f335df12",
   "label": "Lookup RCF",
   "lookupThreshold": null,
   "perUser": false,
   "readOnly": false,
   "required": false,
   "tags": [],
   "type": "Lookup",
   "useDefaultLocale": false,
   "visible": true
   },
   {
   "answerSource": "DEFAULT",
   "confidential": false,
   "defaultAnswer": null,
   "description": null,
   "enabledPasswordEncryption": false,
   "externalId": null,
   "hidden": false,
   "id": "a687eb56-5132-5dfa-fc84-7c17c9b31584",
   "label": "RCF-ORA Test",
   "lookupThreshold": null,
   "perUser": false,
   "readOnly": false,
   "required": false,
   "tags": [],
   "type": "Lookup",
   "useDefaultLocale": false,
   "visible": true
   },
   {
   "answerSource": "DEFAULT",
   "confidential": false,
   "defaultAnswers": [],
   "description": null,
   "enabledPasswordEncryption": false,
   "externalId": null,
   "hidden": false,
   "id": "f2afe6f7-7f87-aea3-36d7-dd119b422cdb",
   "label": "RCF-ORA Test2",
   "perUser": false,
   "questionMultiColumn": {
   "data": [],
   "metaData": []
   },
   "readOnly": false,
   "required": false,
   "tags": [],
   "type": "MultiSelectDropdown",
   "useDefaultLocale": false,
   "visible": true
   },
   {
   "answerSource": "DEFAULT",
   "confidential": false,
   "defaultAnswer": null,
   "description": "<p>Enter the Summary for this object</p>",
   "enabledPasswordEncryption": false,
   "externalId": null,
   "hidden": false,
   "id": "6281d8fe-9058-97ca-04b4-0f48a47e608b",
   "label": "Summary",
   "maxLength": null,
   "perUser": false,
   "readOnly": false,
   "required": true,
   "tags": [],
   "type": "TextField",
   "useDefaultLocale": false,
   "visible": true
   }
   ],
   "perUser": false,
   "title": "Info"
   }
   ],
   "questionnaireGroupId": null,
   "rxId": null,
   "summary": null,
   "useDefaultLanguage": false,
   "workflowId": null
   }
}

Note that since questions can also include answers to dropdown requests, this response can get quite large.

This questionnaire is also from a different service than the submitted request above, so the questions do not match!

The question ids are clearly visible for each question.

Submit Request

The final step is to submit the order with the request created previously.

Sample Submit Service Request
POST http://dwpc.bmcdev.localdomain:8008/api/myit-sb/orders

Headers:

Content-Type: application/json

default-bundle-scope: myit-sb

X-Requested-By: <source application>

Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBQXR1ZXFSY0JUcVJQZVZQSk84eFwvSDVrMmlaeVpoU25ycU1NS28ydGt3dDlUTXBLS0JOYlB6TWV5Q0c0Nk91V2FHeUttQ1ZqV3VvRDc1S1FkVkUwXC92dmZma0d5dmJJT3pxMStXbmdCMVB1cFhYZnNGTVNVaEE9PSIsIm5iZiI6MTU4MzYxMzI1NSwiaXNzIjoidHNpLW15aXRzYi5ibWNkZXYubG9jYWxkb21haW4iLCJfYXV0aFN0cmluZyI6IjFCVVh6UWJYcklNMWs2WVwvekRwMkJNbHJsSFQ1REFRRmZ6UTN4U0tHeUo4MkNLMk1lRlNseEdWbmJHenpxT2lnaE1UbHBGXC93N0o0WmY4UFp3bDBqQmxHakZ6VHNFZ0JYQkFTTnBYNHU3TXhYUk1oWE5WYUVlUT09IiwiZXhwIjoxNTgzNjE2OTc1LCJfY2FjaGVJZCI6MTQ2ODI5LCJpYXQiOjE1ODM2MTMzNzUsImp0aSI6IklER0FBNVYwRkU4WTNBUUdVMVc1UUZXNFFFNkpGUSIsIl9hYnNvbHV0ZUV4cGlyYXRpb25UaW1lIjoxNTgzNjk5Nzc1fQ.eBO42c2QTdqDZSxJEGQIScM1lVMzZ8ST9_MdRqa4rWY

 

data:

{ "requests":[ { "id" : "<request id>" } ] }

 

Sample Submit Service Response

{"id":"11438","requestErrors":[],"requestDetails":[],"expectedDate":null}

 

Sample Submit Request Error Response

Since the input parameters are not checked until the order is submitted, the most likely errors are issues with the input parameters. All errors are returned in the requestErrors array. A sample parameter errors is shown below:

{ "expectedDate": null, "id": null, "requestDetails": [], "requestErrors": [ { "id": "33529", "message": "Required question \"Template\" hasn't been answered", "requestedFor": null, "type": "UNCLASSIFIED" } ] }