Cortex XSOAR Tips & Tricks – Using The API In Automations

This entry is part 4 in the series Cortex XSOAR Tips & Tricks


When developing automations in Cortex XSOAR, you can use the Script Helper in the built-in Cortex XSOAR IDE to view all the scripts and commands available for automating tasks. When there is no script or command available for the specific task you want to automate, you can use the Cortex XSOAR API to automate most tasks available in the web interface.

In this blogpost we will show you how to discover the API endpoints in Cortex XSOAR for specific tasks and which options are available to use them in your own custom automations. As an example we will automate replacing evidences in the incident evidence board.

To enable you to use the Cortex XSOAR API in your own automations, we have created a nitro_execute_http_request function which is available on the NVISO GitHub:

Cortex XSOAR API Endpoints

Before you can use the Cortex XSOAR API in your automation, you will need to know which API endpoints are available. The Cortex XSOAR API documentation can be found in Settings > Integrations > API Keys:

Here you can see the following links:

  • View Cortex XSOAR API: Open the API documentation on the XSOAR server
  • Download Cortex XSOAR API Guide: Download a PDF with the API documentation
  • Download REST swagger file: Download a JSON file which can be imported into a Swagger editor

You can use these links to view all the documented API Endpoints for Cortex XSOAR with the path, parameters and responses including example request body’s and responses. Importing the Swagger JSON file into a Swagger Editor or Postman will allow you to interact with the API for testing without writing a single line of code.

Using The API In Automations

Once you have determined the Cortex XSOAR API endpoint to use, you have 2 options available for use in an automation.

The first option is by using the internalHttpRequest method of the demisto class. This will allow you to do an internal HTTP request on the Cortex XSOAR server. It is the faster of the 2 options but there is a permissions limitation when using this in playbooks. The request runs with the permissions of the executing user, when a command is being executed manually (such as via the War Room or when browsing a widget). When run via a playbook, it will run with a read-only user with limited permissions isolated to the current incident only.

The second option for using the API in automations is the Demisto REST API integration. This integration is part of the Demisto REST API content pack available in the Cortex XSOAR Marketplace.

After installing the content pack, you will need to create an API key in Settings > Integrations > API Keys:

Click on Get Your Key, give it a name and click Generate key:

Copy your key and store it in a secure location:

If you have a multi-tenant environment, you will need to synchronize this key to the different accounts.

Next you will need to configure the Demisto REST API integration:

Click Add instance and copy the API key and click Test to verify that the integration is working correctly:

You will now be able to use the following commands in your automations:

  • demisto-api-delete: send HTTP DELETE request
  • demisto-api-download: Download files from XSOAR server
  • demisto-api-get: send HTTP GET requests
  • demisto-api-multipart: Send HTTP Multipart request to upload files to XSOAR server
  • demisto-api-post: send HTTP POST request
  • demisto-api-put: send HTTP PUT request
  • demisto-delete-incidents: Delete XSOAR incidents

To do HTTP requests when only read permissions are required, you should use the internalHTTPRequest method of the demisto class because it does not require an additional integration and has better performance. From the Demisto REST API integration, you will mostly be using the demisto-api-post command for doing HTTP Post requests in your automations when write permissions are required.


Similar to the demisto.executeCommand method, the demisto.internalHttpRequest does not throw an error when the request fails. Therefore, we have created a nitro_execute_http_request wrapper function to add error handling which you can use in your own custom automations.

import json

def nitro_execute_http_request(method: str, uri: str, body: dict = None) -> dict:
    Send internal http requests to XSOAR server
    :type method: ``str``
    :param method: HTTP Method (GET / POST / PUT / DELETE)
    :type uri: ``str``
    :param uri: Request URI
    :type body: ``dict``
    :param body: Body of request
    :return: dict of response body
    :rtype: ``dict``

    response = demisto.internalHttpRequest(method, uri, body)
    response_body = json.loads(response.get('body'))

    if response.get('statusCode') != 200:
        raise Exception(f"Func: nitro_execute_http_request; {response.get('status')}: {response_body.get('detail')}; "
                        f"error: {response_body.get('error')}")
        return response_body

When you use this function to call demisto.internalHttpRequest, it will return an error when the HTTP request fails:

    uri = "/evidence/search"
    method = "POST"
    body = {"incidentID": '9999999'}

    return_results(nitro_execute_http_request(method=method, uri=uri, body=body))
except Exception as ex:
    return_error(f'Failed to execute nitro_execute_http_request. Error: {str(ex)}')

We have added this custom function to the CommonServerUserPython automation. This automation is created for user-defined code that is merged into each script and integration during execution. It will allow you to use nitro_execute_http_request in all your custom automations.

Incident Evidences Example

To provide you an example of how to use the API in an automation, we will show how to replace evidences in the incident Evidence Board in Cortex XSOAR. We will build on the example of the previous post in this series where we add evidences based on the tags of an entry in the war room:

results = nitro_execute_command(command='getEntries', args={'filter': {'tags': ['evidence']}})

entry_ids = [result.get('ID') for result in results]

for entry_id in entry_ids:
    nitro_execute_command(command='AddEvidence', args={'entryIDs': entry_id, 'desc': 'Example Evidence'})

If you search the script helper in the built-in IDE, you will see that there is already an AddEvidence automation:

When using this command in a playbook to add evidences to the incident Evidence Board, you will get duplicates when the playbooks is run multiple times. This could lead to confusing for the SOC analyst and should be avoided. A replace argument is not available in the AddEvidence command but we can implement this using the Cortex XSOAR API.

To implement the replace functionality, we will first need to search for an entry in the incident Evidence Board with the same description, delete it and then add it again. There are no built-in automations available that support this but it is supported by the Cortex XSOAR API.

If we search the API documentation, we can see the following API Endpoints:

  • /evidence/search
  • /evidence/delete

To search for evidences with the same description, we have created a function:

def nitro_get_incident_evidences(incident_id: str, query: str = None) -> list:
    Get list of incident evidences
    :type incident_id: ``str``
    :param incident_id: XSOAR incident id
    :type query: ``str``
    :param query: query for evidences
    :return: list of evidences
    :rtype: ``list``

    uri = "/evidence/search"
    body = {"incidentID": incident_id}
    if query:
        body.update({"filter": {"query": query}})

    results = nitro_execute_http_request(method='POST', uri=uri, body=body)

    return results.get('evidences', [])

This function uses the wrapper function of the faster internalHTTPRequest method in the demisto class because it does not require write permissions.

To delete the evidences we have created a second function which uses the demisto-api-post command because write permissions are required:

def nitro_delete_incident_evidence(evidence_id: str):
    Delete incident evidence
    :type evidence_id: ``str``
    :param evidence_id: XSOAR evidence id

    uri = '/evidence/delete'
    body = {'evidenceID': evidence_id}

    nitro_execute_command(command='demisto-api-post', args={"uri": uri, "body": body})

We use the nitro_execute_command function we discussed in a previous post in this series to add error handling.

We use these 2 functions to first search for evidences with the same description, delete them and add the tagged war room entries as evidence in the incident Evidence Board again.

description = 'Example Evidence'
incident_id = demisto.incident().get('id)

query = f"description:\"{description}\""
evidences = nitro_get_incident_evidences(incident_id=incident_id, query=query)

for evidence in evidences:

results = nitro_execute_command(command='getEntries', args={'filter': {'tags': ['evidence']}})

entry_ids = [result.get('ID') for result in results]

for entry_id in entry_ids:
    nitro_execute_command(command='AddEvidence', args={'entryIDs': entry_id, 'desc': description })


About the author

Wouter is an expert in the SOAR engineering team in the NVISO SOC. As the SOAR engineering team lead, he is responsible for the development and deployment of automated workflows in Palo Alto Cortex XSOAR which enable the NVISO SOC analysts to faster detect attackers in customers environments. With his experience in cloud and DevOps, he has enabled the SOAR engineering team to automate the development lifecycle and increase operational stability of the SOAR platform.

You can contact Wouter via his LinkedIn page.

Want to learn more about SOAR? Sign- up here and we will inform you about new content and invite you to our SOAR For Fun and Profit webcast.

Series Navigation<< Cortex XSOAR Tips & Tricks – Tagging War Room EntriesCortex XSOAR Tips & Tricks – Exploring the API using Swagger Editor >>

2 thoughts on “Cortex XSOAR Tips & Tricks – Using The API In Automations

Leave a Reply