Core REST API

Use Core REST APIs.

Utilities · Cortex REST API

Details

IDCore REST API
ProviderPalo Alto Networks
CategoryUtilities
From Version5.0.0
Supported ModulesAgentix Cortex Cloud Cloud Runtime Security Cloud Posture Security XSIAM EDR

README

Configure Core REST API in Cortex

Parameter Description Required
Core Server URL For Cortex XSOAR 8 or Cortex XSIAM, use the Copy API URL button on the API Keys page. For Cortex XSOAR 6, use the server URL. True
API Key ID The API Key ID that is linked to the API Key (relevant for Cortex XSIAM and Cortex XSOAR 8.0.0 and above). True
API Key (Password) The core server API key. True
Authentication method Whether authentication should be using “Standard” API key or “Advanced” API key. True
Base marketplace url The base url for the tenant marketplace. False
Trust any certificate (not secure) Trust any certificate (not secure). False
Use system proxy settings Use system proxy settings. False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

Please Note: When updating or making changes to a custom content item (integration, script, list, etc.), it may be necessary to increment the version of the item. To do so, first fetch the current version (usually via a GET command) and then increment the version by 1. Lastly, when updating an item, please use this incremented value for the version field.

core-api-post


send HTTP POST request

Base Command

core-api-post

Input

Argument Name Description Required
uri Request endpoint (e.g. /incident or /public_api/v1/incidents/update_incident). Required
body Body of HTTP POST. Optional

Context Output

There is no context output for this command.

Command Example

!core-api-post uri=/lists/save body={\"name\":\"list_name\",\"data\":\"list_data\"}

Human Readable Output

{“response”:{“commitMessage”:””,”data”:”list_data”,”definitionId”:””,”description”:””,”fromServerVersion”:””,”id”:”list_name”,”itemVersion”:””,”locked”:false,”modified”:”2022-05-29T12:20:14.988577Z”,”name”:”list_name”,”nameLocked”:false,”packID”:””,”prevName”:”list_name”,”primaryTerm”:6,”propagationLabels”:[“all”],”sequenceNumber”:907233,”shouldCommit”:false,”system”:false,”tags”:null,”toServerVersion”:””,”truncated”:false,”type”:”plain_text”,”vcShouldIgnore”:false,”vcShouldKeepItemLegacyProdMachine”:false,”version”:1}}

core-api-get


send HTTP GET requests

Base Command

core-api-get

Input

Argument Name Description Required
uri Request endpoint (e.g. /user or /public_api/v1/rbac/get_users). Required

Context Output

There is no context output for this command.

Command Example

!core-api-get uri=/user

Human Readable Output

{“response”:{“addedSharedDashboards”:[“Threat Intelligence Feeds”,”Troubleshooting Instances”],”allRoles”:[“Administrator”],”defaultAdmin”:true,”email”:”admintest@core.com”,”id”:”admin”,”image”:”8327000###user_image_admin.png”,”lastLogin”:”2022-05-29T15:13:46.224432+03:00”,”name”:”Admin Dude”,”notificationsSettings”:{“email”:{“all”:true},”pushNotifications”:{“all”:true}},”permissions”:{“core”:[“scripts.rwx”,”playbooks.rw”]},”phone”:”+650-123456”,”playgroundId”:”beda-02ab-49ef-8fc1-c43a36f”}}

core-api-put


send HTTP PUT request

Base Command

core-api-put

Input

Argument Name Description Required
uri Request endpoint (e.g. /user). Required
body Request body. Optional

core-api-delete


send HTTP DELETE request

Base Command

core-api-delete

Input

Argument Name Description Required
uri Request endpoint (e.g. /user). Required

Context Output

There is no context output for this command.

Command Example

!core-api-delete uri=/dashboards/9a6cc590-72bb-4ed5-84e9-4577c6d8cbb9

Human Readable Output

{“response”:””}

core-api-download


Download files from core server

Base Command

core-api-download

Input

Argument Name Description Required
uri Request endpoint. Required
filename File name of download. Optional
description Description of file entry. Optional

Context Output

There is no context output for this command.

Command Example

!core-api-download uri=/log/bundle

Context Example

{
    "File": {
        "EntryID": "yukswe2UVanMjyvEANmLBH@bed9ccda-02ab-49ef-8fc1-c43a",
        "Extension": "gz",
        "Info": "gz",
        "MD5": "e4e0a23740dfaa27f00b276af",
        "Name": "logs-bundle-29May2215_14IDT.tar.gz",
        "SHA1": "95e0ebd554ea107f04508d6c2d9e6361",
        "SHA256": "83032a86295279ecdf516b63eae7a7e3e5af301bf4dfed3c82faa23b58",
        "SHA512": "88a3fa0194c7dd439c749b2b0b9cbef64ce18e469d0b8b62bcf18919ffcefd1c99119c993070454d48061357ff0dd0ffe0a070936b62c7ac35035de3",
        "SSDeep": "98304:wAjPMXI9/8BoAKIxrVqJVAw6LgJEBFCH73LOOFdWgiwvSJdBo:3PmI9/8jKIxrVOELrCHwq7O",
        "Size": 4052002,
        "Type": "gzip compressed data, original size modulo 2^32 46240256"
    }
}

Human Readable Output

core-api-multipart


Send HTTP Multipart request to upload files to Core server

Base Command

core-api-multipart

Input

Argument Name Description Required
uri Request endpoint. Required
entryID File entry ID. Required
body Request body. Optional

Context Output

There is no context output for this command.

Command Example

!core-api-multipart uri=/incident/upload/204 entryID=evnKTiujxaZEkeKRxiBMig@bed9ccda-02ab-49ef-8fc1-c43a36ff38f5 body=test_bark

Human Readable Output

{“response”:{“activated”:”0001-01-01T00:00:00Z”,”attachment”:[{“description”:””,”name”:”logs-bundle-29May2214_36IDT.tar.gz”,”path”:”204_34d-836b-4b38-81eb-9b90af9c1a_logs-bundle-29May2214_36IDT.tar.gz”,”showMediaFile”:false,”type”:”application/octet-stream”}],”autime”:1653651342394000,”closed”:”0001-01-01T00:00:00Z”,”created”:”2022-05-27T13:15:51.342394+03:00”,”dueDate”:”0001-01-01T00:00:00Z”,”id”:”204”,”labels”:[{“type”:”Brand”,”value”:”Grafana”},{“type”:”Instance”,”value”:”Grafana_instance_1”}],”modified”:”2022-05-29T12:20:17.196279Z”,”name”:”Adi’s Alert”,”numericId”:204,”occurred”:”2022-05-27T02:02:30Z”,”rawName”:”Adi’s Alert”,”rawType”:”Grafana Alert”,”sequenceNumber”:545,”sourceBrand”:”Grafana”,”sourceInstance”:”Grafana_instance_1”,”type”:”Grafana Alert”,”version”:2}}

core-delete-incidents


Delete Core incidents

Base Command

core-delete-incidents

Input

Argument Name Description Required
ids IDs of the incidents to delete. Required

Context Output

There is no context output for this command.

Command Example

!core-delete-incidents ids=152

Human Readable Output

Core delete incidents

totalDeleted total notUpdated
1 143 0

core-api-install-packs


Upload packs to Core server from url or the marketplace.

Base Command

core-api-install-packs

Input

Argument Name Description Required
packs_to_install The packs to install in JSON format (e.g. [{“AutoFocus”: “2.0.8”}] ). Optional
file_url The pack zip file url. Optional
entry_id The War Room entry ID of the pack zip file. Optional
skip_verify If true will skip pack signature validation, Available from 6.5.0 server version. Optional
skip_validation If true will skip all pack validations, Available from 6.6.0 server version. Optional
timeout_in_seconds The request timeout in seconds. Default value is 180 (3 minutes). Optional

Context Output

There is no context output for this command.

Command Example

!core-api-install-packs packs_to_install=[{"AutoFocus": "2.0.8"}]

Human Readable Output

The following packs installed successfully: AutoFocus

core-api-file-upload


Upload to the incident a file that the user provided according to the entry_id or the content of the file.

Base Command

core-api-file-upload

Input

Argument Name Description Required
incident_id The incident’s ID. Required
file_name The new file’s name. Optional
file_content The new file’s content. Optional
entry_id The War Room entry ID of the pack zip file. Optional

Context Output

There is no context output for this command.

core-api-file-delete


Delete a war room (investigation) file entry.

Base Command

core-api-file-delete

Input

Argument Name Description Required
entry_id The War Room entry ID of the file. Required

Context Output

There is no context output for this command.

core-api-file-attachment-delete


Delete a file attachment from an incident — specifically from the incident’s file attachments (not from the war room).

Base Command

core-api-file-attachment-delete

Input

Argument Name Description Required
incident_id The incident’s ID. Required
file_path The file’s path. Required
field_name Name of the field (type attachment) from which to remove the attachment. Default is attachment. Optional

Command example

!core-api-file-attachment-delete file_path=1@1 incident_id=1

Human Readable Output

Attachment 1@1 deleted.

core-api-file-check


Check if the file exists in Cortex XSOAR (Context) by entry_id.

Base Command

core-api-file-check

Input

Argument Name Description Required
entry_id The War Room entry ID of the file. Required

Context Output

Path Type Description
IsFileExists unknown Dictionary with EntryID as the key and boolean if the file exists as a value.

Configuration parameters

  • url — Core Server URL (required)
  • creds_apikey — API Key ID
  • auth_method — Authentication method
  • marketplace_url — Base marketplace url
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • use_tenant — Use tenant

Commands (20)

  • core-api-delete

    send HTTP DELETE request.

  • core-api-download

    Download files from Core server.

  • core-api-file-attachment-delete

    Delete a file attachment from an incident — specifically from the incident’s file attachments.

  • core-api-file-check

    Check if the file exists in Cortex XSOAR (Context) by entry_id.

  • core-api-file-delete

    Delete a war room (investigation) file entry.

  • core-api-file-upload

    Upload to the incident a file that the user provided according to the entry_id or the content of the file.

  • core-api-get

    send HTTP GET requests.

  • core-api-install-packs

    Upload packs to the core server from the URL or marketplace.

  • core-api-multipart

    Send HTTP Multipart request to upload files to Core server.

  • core-api-post

    send HTTP POST request.

  • core-api-put

    send HTTP PUT request.

  • core-delete-incidents

    Delete Core incidents.

  • demisto-api-delete Deprecated

    Deprecated. Use core-api-delete instead.

  • demisto-api-download Deprecated

    Deprecated. Use core-api-download instead.

  • demisto-api-get Deprecated

    Deprecated. Use core-api-get instead.

  • demisto-api-install-packs Deprecated

    Deprecated. Use core-api-install-packs instead.

  • demisto-api-multipart Deprecated

    Deprecated. Use core-api-multipart instead.

  • demisto-api-post Deprecated

    Deprecated. Use core-api-post instead.

  • demisto-api-put Deprecated

    Deprecated. Use core-api-put instead.

  • demisto-delete-incidents Deprecated

    Deprecated. Use core-delete-incidents instead.


const MIN_HOSTED_XSOAR_VERSION = '8.0.0';
const PLAYBOOK_METADATA = 'playbook_metadata';
const INTEGRATION_NAME = 'CoreRESTAPI';
const xsoar_hosted = ['xsoar', 'xsoar_hosted']
const platform_hosted = ['x2', 'unified_platform']
// Default timeout for HTTP requests (3 minutes in milliseconds)
const default_timeout = 3 * 60 * 1000;

var serverURL = params.url;
if (serverURL.slice(-1) === '/') {
    serverURL = serverURL.slice(0,-1);
}

// returns true if the current platform is XSIAM or XSOAR 8.0 and above.
isHosted = function () {
    res = getDemistoVersion();
    platform = res.platform;
    if  ((xsoar_hosted.includes(platform) && isDemistoVersionGE(MIN_HOSTED_XSOAR_VERSION)) || platform_hosted.includes(platform)) {
        return true
    }
    return false
}

var marketplace_url = params.marketplace_url? params.marketplace_url : 'https://marketplace.xsoar.paloaltonetworks.com/content/packs/'

getTenantAccountName = function () {
    // example: for 'https://account-testing-ysdkvou:443/acc_Test' will return 'acc_Test'
    const urls = demistoUrls()
    const server_url = urls['server'].toString()
    // server_url example - https://account-testing-ysdkvou:443/acc_Test
    var account_name = ''
    // check if server_url contains "/acc_" string
    if (server_url.indexOf("/acc_") >= 0){
        const words = server_url.split('acc_')
        const tenant_name = words[words.length - 1]
        if (tenant_name !== "") {
            account_name = 'acc_' + tenant_name
        }
    }
    else{
        logDebug('getTenantAccountName: The server url ' + server_url + ' does not contain the expected tenant prefix acc_');
    }
    return account_name
}

getStandardAuthMethodHeaders = function(key, auth_id, content_type) {
    return {
                'Authorization': [key],
                'x-xdr-auth-id': [auth_id],
                'Content-Type': [content_type],
                'Accept': ['application/json']
            }
}

getAdvancedAuthMethodHeaders = function(key, auth_id, content_type,) {
    const nonce = Array.from({length: 64}, () => Math.random().toString(36).charAt(2)).join("");
    const timestamp = Date.now().toString();
    var auth_key = key + nonce + timestamp
    auth_key = unescape(encodeURIComponent(auth_key));
    const auth_key_hash = SHA256_hash(auth_key)

    return {
                'x-xdr-timestamp': [timestamp],
                'x-xdr-nonce': [nonce],
                'x-xdr-auth-id': [auth_id],
                'Authorization': [auth_key_hash],
                'Content-Type': [content_type],
                'Accept': ['application/json']
            }
    }

getRequestURL = function (uri) {
    var requestUrl = serverURL;

    // only when using XSIAM or XSOAR >= 8.0 we will add the /xsoar suffix
    // and only when it is not a /public_api or /platform endpoint.
    if (isHosted()) {
        const isPublicApi = uri.startsWith('/public_api');
        const isPlatformApi = uri.startsWith('/platform');
        const isXsoarApi = serverURL.endsWith('/xsoar');

        if (!isXsoarApi && !isPublicApi && !isPlatformApi) {
            requestUrl += '/xsoar';
        }
    }
    if (params.use_tenant){
        requestUrl += '/' + getTenantAccountName();
    }
    if (uri.slice(0, 1) !== '/') {
        requestUrl += '/';
    }
    requestUrl += uri;
    return requestUrl;
}

sendMultipart = function (uri, entryID, body, timeoutInMilliseconds) {
    var requestUrl = getRequestURL(uri)
    try {
        body = JSON.parse(body);
    } catch (ex) {
        // do nothing, use the body as is in the request.
        logDebug('could not parse body as a JSON object, passing as is. body: ' + JSON.stringify(body));
    }
    var key = params.apikey? params.apikey : (params.creds_apikey? params.creds_apikey.password : '');
    if (key == ''){
        throw 'API Key must be provided.';
    }
    var auth_id = params.auth_id? params.auth_id : (params.creds_apikey? params.creds_apikey.identifier : '');
    var headers = {}
    // in case the integration was installed before auth_method was added, the auth_method param will be empty so
    // we will use the standard auth method
    if (!params.auth_method || params.auth_method == 'Standard'){
        headers = getStandardAuthMethodHeaders(key, auth_id, 'multipart/form-data')
    }
    else if (params.auth_method == 'Advanced') {
        headers = getAdvancedAuthMethodHeaders(key, auth_id, 'multipart/form-data')
    }
    // Default timeout to 3 minutes if not provided
    timeoutInMilliseconds = timeoutInMilliseconds ? timeoutInMilliseconds : 3 * 60 * 1000; // timeout in milliseconds

    var res;
    var tries = 0;
    do {
        logDebug('Calling httpMultipart from sendMultipart, try number ' + tries + ', with requestUrl = ' + requestUrl + ', entryID = ' + entryID + ', body = ' + JSON.stringify(body) + ', insecure = ' + params.insecure + ', proxy = ' + params.proxy + ', undefined = ' + undefined + ', file, ' + ' timeout in milliseconds = ' + timeoutInMilliseconds);
        res = httpMultipart(
            requestUrl,
            entryID,
            {
                Headers: headers,
            },
            body,
            params.insecure,
            params.proxy,
            undefined,
            'file',
            undefined,
            undefined,
            timeoutInMilliseconds
        );
        logDebug('The result of calling httpMultipart, with the requestUrl = ' + requestUrl + ' is ' + res.Status + ' and res is ' + JSON.stringify(res))
        tries++;
    } while (tries < 3 && res.Status.startsWith('timeout'));
    logDebug("Ran httpMultipart() " + tries + " time(s)")

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        logDebug('httpMultipart request to requestUrl = ' + requestUrl + ' failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.');
        throw 'Core REST APIs - Request to requestUrl = ' + requestUrl + ' Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
    }
    logDebug('httpMultipart request to requestUrl = ' + requestUrl + ' was successful.');

    try {
        var response = res.Body;
        try {
            response = JSON.parse(res.Body);
        } catch (ex) {
            // do nothing, already handled prior the try/catch
        }
        return {response: response};
    } catch (ex) {
        throw 'Core REST APIs - Error parsing response in httpMultipart request - ' + ex + '\nBody:' + res.Body;
    }

};

var addPlaybookMetadataToRequest = function(body, command) {
    try {
        var requestBodyObject = JSON.parse(body);
        var playbookTaskInfoJson = JSON.parse(playbookTaskInfo);
        requestBodyObject.request_data.playbook_metadata = {
            'playbook_id': playbookTaskInfoJson.playbookID,
            'playbook_name': playbookTaskInfoJson.playbookName,
            'task_id': playbookTaskInfoJson.taskID,
            'task_name': playbookTaskInfoJson.taskName,
            'integration_name': INTEGRATION_NAME,
            'command_name': command,
        }
        logDebug("Added playbook-metadata to request body " + requestBodyObject.request_data.playbook_metadata);
    } catch(error) {
        logError("Error parsing as a JSON object playbookTaskInfo: " + error);
    } finally {
        body = JSON.stringify(requestBodyObject);
    }
    return body;
};


var sendRequest = function(method, uri, body, raw, timeout = default_timeout) {
    var requestUrl = getRequestURL(uri);

    var key = params.apikey ? params.apikey : (params.creds_apikey ? params.creds_apikey.password : '');
    if (key == '') {
        throw 'API Key must be provided.';
    }

    var auth_id = params.auth_id ? params.auth_id : (params.creds_apikey ? params.creds_apikey.identifier : '');

    var headers = {};
    if (!params.auth_method || params.auth_method == 'Standard') {
        headers = getStandardAuthMethodHeaders(key, auth_id, 'application/json');
    } else if (params.auth_method == 'Advanced') {
        if (!auth_id) {
            throw 'Core REST APIs - please choose "Standard Authentication method" or provide the API Key ID.';
        }
        headers = getAdvancedAuthMethodHeaders(key, auth_id, 'application/json');
    }

    if (requestUrl.includes("start_xql_query") && method === 'POST') {
        body = addPlaybookMetadataToRequest(body, command);
    }

    var res;
    var tries = 0;
    var maxTries = 3;

    do {
        logDebug('Calling http() from sendRequest, try number ' + tries);

        res = http(
            requestUrl,
            {
                Method: method,
                Headers: headers,
                Body: body,
                SaveToFile: raw
            },
            params.insecure,
            params.proxy,
            undefined,
            undefined,
            timeout
        );

        logDebug(
            'Result of http() requestUrl = ' + requestUrl +
            ' status = ' + res.Status);

        tries++;

    } while (tries < maxTries && res.Status && res.Status.startsWith('timeout'));

    logDebug("Ran http() " + tries + " time(s)");

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        logDebug('http() request failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res));
        throw 'Core REST APIs - Request to requestUrl = ' + requestUrl +
              ' Failed.\nStatus code: ' + res.StatusCode +
              '.\nBody: ' + JSON.stringify(res);
    }

    logDebug('http() request was successful.');

    if (raw) {
        return res;
    }

    try {
        var response = res.Body;
        try {
            response = JSON.parse(res.Body);
        } catch (ex) {
            // keep raw body if not JSON
        }
        return { response: response };
    } catch (ex) {
        throw 'Core REST APIs - Error parsing response - http() request to requestUrl = ' +
              requestUrl + '\nError: ' + ex + '\nBody:' + res.Body;
    }
};

function reduce_data(data, keep_fields) {
    var new_d = {};
    for (var field_index = 0; field_index < keep_fields.length; field_index += 1) {
        var field = keep_fields[field_index];
        if (field in data) {
            new_d[field] = data[field];
        }
    }
    return new_d;
}

var deleteIncidents = function(ids_to_delete) {
    var body = {
        ids: ids_to_delete,
        all: false,
        filter: {"size": 1},
        excludeIncidentsResponseData: true // exclude unrelated data in response
    };

    var res = sendRequest('POST', '/incident/batchDelete', JSON.stringify(body));
    if (isError(res[0])) {
        throw res[0].Contents;
    }
    
    var relevant_headers = ['totalDeleted', "notUpdated", 'total']
    var response = reduce_data(res['response'], relevant_headers)

    var md = tableToMarkdown('Core delete incidents', response);

    return {
        ContentsFormat: formats.json,
        Type: entryTypes.note,
        Contents: {"response": response},
        HumanReadable: md
    };
};

var installPack = function(pack_url, entry_id, skip_verify, skip_validation, timeoutInSeconds){
    let file_path;
    // Convert timeout from seconds to milliseconds, default to 180 seconds (3 minutes)
    var timeoutInMilliseconds = timeoutInSeconds ? parseInt(timeoutInSeconds) * 1000 : 3 * 60 * 1000;
    
    if (entry_id){
        file_path = entry_id;
    }
    else{
        var method = 'GET';
        var save_to_file = true;
        // download pack zip file
        logDebug('Calling http() from installPack, with pack_url = ' + pack_url + ', Method = ' + method + ', SaveToFile = ' + save_to_file + ', timeout in milliseconds = ' + timeoutInMilliseconds);
        var res = http(
        pack_url,
        {
            Method: method,
            Headers: {},
            SaveToFile: save_to_file
        },
        undefined,
        undefined,
        undefined,
        undefined,
        timeoutInMilliseconds
        );

        if (res.StatusCode < 200 || res.StatusCode >= 300) {
            throw 'Core REST APIs - Failed to download pack file from ' + pack_url;
        }
        file_path = res.Path;
        logDebug('The result of http() from installPack, to pack_url = ' + pack_url + ' is ' + res.StatusCode)
    }

    let upload_url = 'contentpacks/installed/upload?'

    // set the skipVerify parameter
    if(isDemistoVersionGE('6.5.0')){
        if (skip_verify && skip_verify === 'false') {
            upload_url+='skipVerify=false'
        }else{
            upload_url+='skipVerify=true'
        }
    }

    // set the skipValidation parameter
    if(isDemistoVersionGE('6.6.0')){
        if (skip_validation && skip_validation === 'false') {
            upload_url+='&skipValidation=false'
        }else{
            upload_url+='&skipValidation=true'
        }
    }
    // upload the pack
    sendMultipart(upload_url, file_path,'{}', timeoutInMilliseconds);
};

var installPacks = function(packs_to_install, file_url, entry_id, skip_verify, skip_validation, timeoutInSeconds = 3 * 60) {
    if ((!packs_to_install) && (!file_url) && (!entry_id)) {
        throw 'Either packs_to_install, file_url or entry_id argument must be provided.';
    }
    else if (file_url) {
        installPack(file_url, undefined, skip_verify, skip_validation, timeoutInSeconds)
        logDebug('Pack installed successfully from ' + file_url)
        return 'The pack installed successfully from the file ' + file_url
    }
    else if (entry_id) {
        installPack(undefined, entry_id, skip_verify, skip_validation, timeoutInSeconds)
        logDebug('The pack installed successfully from the file.')
        return 'The pack installed successfully from the file.'
    }
    else{
        let installed_packs = []
        let packs = JSON.parse(packs_to_install);

        for (let pack_index = 0; pack_index < packs.length; pack_index += 1) {
            let pack = packs[pack_index];
            let pack_id = Object.keys(pack)[0]
            let pack_version = pack[pack_id]

            let pack_url = '{0}{1}/{2}/{3}.zip'.format(marketplace_url,pack_id,pack_version,pack_id)
            installPack(pack_url, undefined, skip_verify, skip_validation, timeoutInSeconds)
            logDebug(pack_id + ' pack installed successfully')
            installed_packs.push(pack_id)
        }
        if (installed_packs.length === 0) {
            return 'No pack has been installed, please check that the pack name and version are correct.'
        } else {
            return 'The following packs installed successfully: ' + installed_packs.join(", ")
        }
    }
};


/* helper functions */

/**
 * deletes an entry  by entryID by the key_to_delete
Arguments:
    @param {String} incident_id  -- the incident id
    @param {String} entry_id  -- the entry ID of the file
Returns:
    CommandResults
"""
 */
var uploadFile= function(incident_id, entry_id) {
    timeout = 3 * 60 * 1000; // timeout in milliseconds
    logDebug('Calling httpMultipart from uploadFile, with the url /entry/upload/' + incident_id + ' and entry_id = ' + entry_id + ', timeout in milliseconds = ' + timeout);
    var res = httpMultipart(`/entry/upload/${incident_id}`, entry_id, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, timeout);
    logDebug('After Calling to httpMultipart with the url /entry/upload/' + incident_id + ' and entry_id = ' + entry_id + '. The satus code: ' + res.StatusCode);
    if (isError(res[0])) {
        throw res[0].Contents;
    }
    return res;
};


/**
 * deletes a file  by entryID
Arguments:
    @param {String} delete_artifact  -- in order to delete the artifact
    @param {String} entry_id  -- entry ID of the file
Returns:
    CommandResults
"""
 */
var deleteFileRequest = function (entry_id, delete_artifact = true) {
    const body_content = JSON.stringify({
        id: entry_id,
        deleteArtifact: delete_artifact});

    return sendRequest( 'POST', '/entry/delete/v2', body_content);
};


/**
 * Sends http request to delete attachment
Arguments:
    @param {String} incident_id  -- incident id to upload the file to
    @param {String} file_path -- the file path to delete
    @param {String} field_name  -- Name of the field (type attachment) you want to remove the attachment
Returns:
    Results
"""
 */
var deleteAttachmentRequest=function(incident_id, attachment_path, field_name = 'attachment') {
    body = JSON.stringify({
        fieldName: field_name,
        files: {
          [attachment_path]: {
            path: attachment_path
          }
        },
        originalAttachments: [
          {
            path: attachment_path
          }
        ]
      });
    try{
        return sendRequest('POST', `/incident/remove/${incident_id}`, body);
    }
    catch (e) {
        throw new Error(`File already deleted or not found.\n${e}`);
    }
};

/**
 * Upload a new file
Arguments:
    @param {String} incident_id  -- incident id to upload the file to
    @param {String} file_content -- content of the file to upload
    @param {String} file_name  -- name of the file in the dest incident
    @param {String} entryID  -- entry ID of the file
Returns:
    CommandResults -- Readable output
Note:
    You can give either the entryID or file_name.
"""
 */
var fileUploadCommand = function(incident_id, file_content, file_name, entryID ) {
    incident_id = (typeof incident_id === 'undefined')? investigation.id: incident_id;
    if (incident_id!=investigation.id){
        log(`Note that the file would be uploaded to ${incident_id} from incident ${investigation.id}`);
    }
    if ((!file_name) && (!entryID)) {
        throw 'Either file_name or entry_id argument must be provided.';
    }
    var fileId = '';
    if ((!entryID)) {
        logDebug('Calling saveFile for the file ' + file_name);
        fileId = saveFile(file_content);
        logDebug('Calling uploadFile for the incident ' + incident_id + ' with fileId = ' + fileId);
        response = uploadFile(incident_id, fileId);
        logDebug('After the call to uploadFile for the incident ' + incident_id + ' with fileId = ' + fileId + '. Status code: ' + response.StatusCode);
    } else {
        if (file_name === undefined) {
            logDebug('Calling dq with the invContext of incident ' + incident_id + ' and the transformation string: File(val.EntryID == ${entryID}).Name');
            file_name = dq(invContext, `File(val.EntryID == ${entryID}).Name`);
            logDebug('After calling dq. The returned file name is ' + file_name + '. The parameters were the invContext of incident ' + incident_id + ' and the transformation string: File(val.EntryID == ${entryID}).Name');
        }
        if (Array.isArray(file_name)) {
            if (file_name.length > 0) {
                file_name = file_name[0];
            } else {
                file_name = undefined;
            }
        }
        response_multi= sendMultipart(`/incident/upload/${incident_id}`,entryID,'{}');
        return `The file ${entryID} uploaded successfully to incident ${incident_id}. `;
        }
    var md = `File ${file_name} uploaded successfully to incident ${incident_id}.`;
    fileId = file_name ? fileId : entryID;
    return {
        Type: entryTypes.file,
        FileID: fileId,
        File: file_name,
        Contents: file_content,
        HumanReadable: md
    };
};



/**
 * Deletes a specific file.
Arguments:
    @param {String} entryId  -- entry ID of the file
Returns:
    Message that the file was deleted successfully + entry_id
"""
 */
// getting the context data
var fileDeleteCommand = function(EntryID) {
    files =  invContext['File'];
    if (!files){
        throw new Error(`Files not found.`);
    }
    files = (invContext['File'] instanceof Array)? invContext['File']:[invContext['File']];
    if (files[0]=='undefined'){
        throw new Error(`Files not found.`);

    }
    var not_found = true
    for (var i = 0 ;i <=Object.keys(files).length - 1;  i++) {
        if (files[i]['EntryID'] == EntryID) {
            not_found= false
        }

      }
    if(not_found){
        throw new Error(`File already deleted or not found.`);
    }
    deleteFileRequest(EntryID);
    return  {Type: entryTypes.note,
        Contents: '',
        ContentsType: formats.json,
        HumanReadable: `File ${EntryID} was deleted successfully.`}
}


/**
 This command checks if the file is existing.
    Arguments:
        @param {String} EntryID  -- entry ID of the file
    Returns:
        Dictionary with EntryID as key and boolean if the file exists as value.
*/
function coreApiFileCheckCommand(EntryID) {
    files =  invContext['File']instanceof Array? invContext['File']:[invContext['File']];
    var file_found = false;
    var human_readable = `File ${EntryID} does not exist`;
    if (typeof files['0'] !== 'undefined') {
        for (var i = 0 ;i <=Object.keys(files).length - 1;  i++) {
            if (files[i]['EntryID'] == EntryID) {
                file_found= true ;
                human_readable = `File ${EntryID} exists`;
            }
          }
    }
    return {
        Type: entryTypes.note,
        Contents: {[EntryID]:file_found},
        HumanReadable: human_readable,
        EntryContext: {[`IsFileExists(val.${EntryID}==${EntryID})`]:{[EntryID]:file_found}}
    };


};

/**
 This command deletes attachment from an incident.
    Arguments:
        @param {String} incident_id  -- incident id to delete the file from
        @param {String} attachment_path -- the file path
        @param {String} field_name  -- Name of the field (type attachment) you want to remove the attachment
    Returns:
        Show a message that the file was deleted successfully
*/
var fileDeleteAttachmentCommand = function (attachment_path, incident_id, field_name){
    incident_id = (typeof incident_id == 'undefined')? investigation.id: incident_id;
    deleteAttachmentRequest(incident_id, attachment_path, field_name);
    return `Attachment ${attachment_path} deleted `;
};



switch (command) {
    case 'test-module':
        res = sendRequest('GET','user');  // throws an exception if the request fails
        return 'ok';
    case 'demisto-api-post':
    case 'core-api-post':
        if(args.body)
            var body = JSON.parse(args.body);
        else
            logDebug('The body is empty.');
        var timeout; // Declare timeout.
        if (args.timeout) {
            var parsedTimeout = parseInt(args.timeout);
            if (!isNaN(parsedTimeout) && parsedTimeout >= 0) {
                timeout = parsedTimeout * 60 * 1000; // timeout in milliseconds
                logDebug('Timeout was set to ' + timeout + ' milliseconds.');
            }
        }
        if (!timeout) {
            timeout = default_timeout; // Default 3 minutes timeout
            logDebug('Timeout was not provided or it is invalid. Will use the default 3 minutes timeout.');
        }

        return sendRequest('POST', args.uri, args.body, false, timeout);
    case 'demisto-api-get':
    case 'core-api-get':
        return sendRequest('GET',args.uri);
    case 'demisto-api-put':
    case 'core-api-put':
        var body = JSON.parse(args.body);
        return sendRequest('PUT',args.uri, args.body);
    case 'demisto-api-delete':
    case 'core-api-delete':
        return sendRequest('DELETE',args.uri);
    case 'demisto-api-multipart':
    case 'core-api-multipart':
        return sendMultipart(args.uri, args.entryID, args.body);
    case 'demisto-api-download':
    case 'core-api-download':
        var res = sendRequest('GET',args.uri,args.body,true);
        var filename = res.Path;
        if (args.filename) {
            filename = args.filename;
        } else {
            var disposition = res.Headers['Content-Disposition'][0].split('=');
            if (disposition.length === 2) {
                filename = disposition[1];
            }
        }
        var desc = args.description || '';
        return ({Type: entryTypes.file, FileID: res.Path, File: filename, Contents: desc});
    case 'demisto-delete-incidents':
    case 'core-delete-incidents':
        var ids = argToList(args.ids);
        return deleteIncidents(ids);
    case 'demisto-api-install-packs':
    case 'core-api-install-packs':
        return installPacks(args.packs_to_install, args.file_url, args.entry_id, args.skip_verify, args.skip_validation, args.timeout_in_seconds);
    case 'core-api-file-upload':
        return fileUploadCommand(args.incident_id, args.file_content, args.file_name, args.entry_id)
    case 'core-api-file-delete':
        return fileDeleteCommand(args.entry_id);
    case 'core-api-file-attachment-delete':
        return fileDeleteAttachmentCommand(args.file_path, args.incident_id, args.field_name);
    case 'core-api-file-check':
        return coreApiFileCheckCommand(args.entry_id);
    default:
        throw 'Core REST APIs - unknown command';
}