{ "name": "Tenable IO Assets", "vendor_identifier": "Tenable IO", "comment": "Tenable IO Assets management", "version": "5.0", "type": "REST_EVENT", "event_type": [ "FIXED_ADDRESS_IPV4", "FIXED_ADDRESS_IPV6", "HOST_ADDRESS_IPV4", "HOST_ADDRESS_IPV6" ], "content_type": "application/json", "quoting": "XMLA", "headers": { "X-apikeys": "accessKey=${S:A:accessKey};secretKey=${S:A:secretKey}", "vendor": "Infoblox", "product": "Infoblox_Outbound_Notification", "build": "1.0.2" }, "steps": [{ "name": "DebugStart", "operation": "NOP", "body": "${XC:DEBUG:{H:}}${XC:DEBUG:{E:}}${XC:DEBUG:{I:}}${XC:DEBUG:{L:}}${XC:DEBUG:{S:}}${XC:DEBUG:{P:}}${XC:DEBUG:{R:}}${XC:DEBUG:{RH:}}${XC:DEBUG:{UT:}}" }, { "name": "verifyModifyChecks", "comment": "Check for operation MODIFY.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:operation_type}", "op": "==", "right": "MODIFY" }], "else_next": "checkEventTypeHost" } }, { "name": "verifyEAsforModifyingAsset", "comment": "Verify EAs for modifying asset.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "==", "right": "true" }], "else_stop": true } }, { "name": "formatThisTimestamp", "comment": "Format the event (this) timestamp to a string so we can truncate it to the minute.", "operation": "NOP", "body_list": [ "${XC:COPY:{L:ThisFormattedTimestamp}:{E:timestamp}}${XC:FORMAT:DATE_EPOCH:{L:ThisFormattedTimestamp}}${XC:FORMAT:DATE_STRFTIME:{L:ThisFormattedTimestamp}:{%a, %d %b %Y %H:%M:%S}}${XC:FORMAT:TRUNCATE:{L:ThisFormattedTimestamp}:{-3t}}" ] }, { "name": "formatLastTimestamp", "comment": "If the timestamp EA is empty there is no need to check the last time it has been scanned. Format the TNBL_IO_Sync_Time EA timestamp to a string so we can truncate it to the minute.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Sync_Time}{value}}", "op": "==", "right": "" }], "next": "checkEventTypeHost", "else_eval": "${XC:COPY:{L:LastFormattedTimestamp}:{E:values{extattrs}{TNBL_IO_Sync_Time}{value}}}${XC:FORMAT:DATE_EPOCH:{L:LastFormattedTimestamp}}${XC:FORMAT:DATE_STRFTIME:{L:LastFormattedTimestamp}:{%a, %d %b %Y %H:%M:%S}}${XC:FORMAT:TRUNCATE:{L:LastFormattedTimestamp}:{-3t}}" } }, { "name": "compareTimestamps", "comment": "If this timestamp and the last one have the same minute, stop the template. This prevents the many NIOS MODIFY events that occur after another event (not sure why this happens) from being sent to Tenable, creating many empty 'Asset Seen' notifications for an asset", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:ThisFormattedTimestamp}", "op": "==", "right": "${L:A:LastFormattedTimestamp}" }], "stop": true } }, { "name": "checkEmptyEAsDifferencesModify", "comment": "If any previous_values is empty, means the Device Type has changed. We can grab the new one.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:previous_values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "==", "right": "" } ], "next": "checkEventTypeHost" } }, { "name": "checkEAsDifferencesModify", "comment": "Check EA changes. Don't MODIFY anything if only the EAs changed.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:previous_values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Asset_Sync}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Sync}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Sync}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Scan}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Scan}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Scan_On_Add}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Scan_On_Add}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Add_by_Hostname}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Add_by_Hostname}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Target_Group}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Target_Group}{value}}" }, { "left": "${E:A:previous_values{extattrs}{TNBL_IO_Scan_Template}{value}}", "op": "!=", "right": "${E:A:values{extattrs}{TNBL_IO_Scan_Template}{value}}" } ], "stop": true } }, { "name": "checkMacModifyEmpty", "comment": "If the user adds a MAC to an asset that previously did not have one we can just add the asset as usual. Tenable does not support removing a MAC from an asset.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:previous_values{mac}}", "op": "==", "right": "" } ], "next": "checkEventTypeHost" } }, { "name": "checkMacModify", "comment": "Since the MAC is a primary key, if it changed, we need to delete the asset with the old MAC and readd this new one.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:previous_values{mac}}", "op": "==", "right": "${E:A:values{mac}}" } ], "next": "checkEventTypeHost" } }, { "name": "deleteAssetModifyMac", "comment": "Delete asset using its MAC when MODIFYING a MAC in NIOS. Then we can add the new MAC as a new asset as normal.", "operation": "POST", "parse": "JSON", "transport": { "path": "/api/v2/assets/bulk-jobs/delete" }, "result": [{ "codes": "200,202", "next": "checkEventTypeHost" }], "body_list": [ "{", "\"query\": {", "\"field\": \"mac_address\",", "\"operator\": \"eq\",", "\"value\": \"${E:A:previous_values{mac}}\"", "},", "\"hard_delete\": true", "}" ] }, { "name": "checkEventTypeHost", "comment": "Check HOST event type.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "HOST" }], "eval": "${XC:COPY:{L:TNBL_IO_Scan_Template}:{E:values{extattrs}{TNBL_IO_Scan_Template}{value}}}${XC:COPY:{L:TNBL_IO_Target_Group}:{E:values{extattrs}{TNBL_IO_Target_Group}{value}}}${XC:ASSIGN:{L:operating_system}:{S:}}${XC:ASSIGN:{L:source}:{S:NIOS}}${XC:ASSIGN:{L:Path}:{S:record:host}}", "else_next": "checkEventTypeFixed" } }, { "name": "checkHostIPv4", "comment": "Verify an IPv4 exists for a HOST.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "IPV4" }, { "left": "${E:A:values{ipv4addr}}", "op": "!=", "right": "" } ], "next": "checkHostAddByHostname", "eval": "${XC:COPY:{L:ThisIP}:{E:values{ipv4addr}}}${XC:COPY:{L:TargetEntry}:{E:values{ipv4addr}}}${XC:ASSIGN:{L:IPvTypeForRequests}:{S:ipv4addr}}${XC:ASSIGN:{L:IPvTypeForAssets}:{S:ipv4}}" } }, { "name": "checkHostIPv6", "comment": "Verify an IPv6 exists for a HOST.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "IPV6" }, { "left": "${E:A:values{ipv6addr}}", "op": "!=", "right": "" } ], "eval": "${XC:COPY:{L:ThisIP}:{E:values{ipv6addr}}}${XC:COPY:{L:TargetEntry}:{E:values{ipv6addr}}}${XC:ASSIGN:{L:IPvTypeForRequests}:{S:ipv6addr}}${XC:ASSIGN:{L:IPvTypeForAssets}:{S:ipv6}}", "else_error": true } }, { "name": "checkHostAddByHostname", "comment": "Check if user wants to add the Target Entry using its hostname instead of its IP.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Add_by_Hostname}{value}}", "op": "==", "right": "true" }, { "left": "${E:A:values{host}}", "op": "!=", "right": "" } ], "eval": "${XC:COPY:{L:TargetEntry}:{E:values{host}}" } }, { "name": "setHostName", "comment": "If an IPv4 or IPv6 host has a name we can use it as a netbios_name for asset posting.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{host}}", "op": "==", "right": "" }], "eval": "${XC:ASSIGN:{L:netbios_name}:{S:}}", "else_eval": "${XC:COPY:{L:netbios_name}:{E:values{host}}}", "next": "checkIPv4ForMACAddress", "else_next": "checkIPv4ForMACAddress" } }, { "name": "checkEventTypeFixed", "comment": "Check FIXED event type.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "FIXED" }], "eval": "${XC:COPY:{L:TNBL_IO_Scan_Template}:{E:values{extattrs}{TNBL_IO_Scan_Template}{value}}}${XC:COPY:{L:TNBL_IO_Target_Group}:{E:values{extattrs}{TNBL_IO_Target_Group}{value}}}${XC:ASSIGN:{L:operating_system}:{S:}}${XC:ASSIGN:{L:source}:{S:NIOS}}${XC:ASSIGN:{L:Path}:{S:fixedaddress}}", "else_stop": true } }, { "name": "checkFixedIPv4", "comment": "Verify an IPv4 exists for a FIXED.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "IPV4" }, { "left": "${E:A:values{ipv4addr}}", "op": "!=", "right": "" } ], "next": "setFixedName", "eval": "${XC:COPY:{L:ThisIP}:{E:values{ipv4addr}}}${XC:COPY:{L:TargetEntry}:{E:values{ipv4addr}}}${XC:ASSIGN:{L:IPvTypeForRequests}:{S:ipv4addr}}${XC:ASSIGN:{L:IPvTypeForAssets}:{S:ipv4}}" } }, { "name": "checkFixedIPv6", "comment": "Verify an IPv6 exists for a FIXED.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "IPV6" }, { "left": "${E:A:values{ipv6addr}}", "op": "!=", "right": "" } ], "eval": "${XC:COPY:{L:ThisIP}:{E:values{ipv6addr}}}${XC:COPY:{L:TargetEntry}:{E:values{ipv6addr}}}${XC:ASSIGN:{L:IPvTypeForRequests}:{S:ipv6addr}}${XC:ASSIGN:{L:IPvTypeForAssets}:{S:ipv6}}${XC:ASSIGN:{L:Path}:{S:ipv6fixedaddress}}", "else_error": true } }, { "name": "setFixedName", "comment": "If an IPv4 or IPv6 fixed address has a name we can use it as a netbios_name for asset posting. We must use a separate step here from setHostName because the {name} is different in the E namespace.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{name}}", "op": "==", "right": "" }], "eval": "${XC:ASSIGN:{L:netbios_name}:{S:}}", "else_eval": "${XC:COPY:{L:netbios_name}:{E:values{name}}}" } }, { "name": "checkIPv4ForMACAddress", "comment": "If an IPv4 address has a MAC we can use it as a mac_address for asset posting. Does not work for IPv6 because they have DUIDS, not MACs, and DUIDs are not currently supported by TenableIO. Set it to empty if IPv6 because Infoblox doesn't ignore nonexitent locals for later asset posting.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "IPV4" }], "else_next": "getDeviceType", "else_eval": "${XC:ASSIGN:{L:mac_address}:{S:}}" } }, { "name": "setMACAddress", "comment": "Set the mac_address for a host or fixed if it exists. The second condition is a workaround for an IPv4 Reservation in Infoblox. When created, it is automatically assigned the mac 00:00:00:00:00:00, which creates unexpected results in TenableIO since a mac address is a primary key. This workaround sets it to empty so it is not added when posting an asset.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:values{mac}}", "op": "==", "right": "" }, { "left": "${E:A:values{mac}}", "op": "==", "right": "00:00:00:00:00:00" } ], "eval": "${XC:ASSIGN:{L:mac_address}:{S:}}", "else_eval": "${XC:COPY:{L:mac_address}:{E:values{mac}}}" } }, { "name": "getDeviceType", "comment": "If an IPv4 or IPv6 host/fixed has a device type we can use it as the OS for asset posting", "operation": "GET", "wapi": "v2.7", "parse": "JSON", "transport": { "path": "${L:A:Path}?${L:A:IPvTypeForRequests}=${L:A:ThisIP}&_return_fields=device_type" } }, { "name": "setDeviceType", "comment": "If the device_type is not empty, set it to the OS.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${P:A:PARSE[0]{device_type}}", "op": "!=", "right": "" }], "eval": "${XC:COPY:{L:operating_system}:{P:PARSE[0]{device_type}}}" } }, { "name": "checkOperationTypeDelete", "comment": "Check for DELETE operation type. If DELETE, skip Target Group adding and scanning.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:operation_type}", "op": "=~", "right": "DELETE" }], "next": "deleteAsset" } }, { "name": "skipGettingHost_refIfFixed", "comment": " Skip getting record _refs if FIXED. Before we add to the target, scan or add the asset, get the object ref now because we update the timestamp using the _ref as the template executes. This makes it easier to troubleshoot and follow execution by looking at the timestamps in Infoblox, etc.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "FIXED" }], "next": "set_ref" } }, { "name": "getHost_ref", "comment": "Get host _ref.", "operation": "GET", "wapi": "v2.7", "transport": { "path": "record:host?${L:A:IPvTypeForRequests}=${L:U:ThisIP}&network_view=${E:U:values{network_view}}&_return_fields=extattrs" } }, { "name": "setHost_ref", "comment": "Set host _ref.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${P:A:PARSE[0]{_ref}}", "op": "!=", "right": "" }], "eval": "${XC:COPY:{L:Obj_ref}:{P:PARSE[0]{_ref}}}", "next": "checkOperationTypeModify" } }, { "name": "set_ref", "comment": "Set _ref for items that are not HOSTs.", "operation": "NOP", "body_list": [ "${XC:COPY:{L:Obj_ref}:{E:values{_ref}}}" ] }, { "name": "checkOperationTypeModify", "comment": "Check for operation MODIFY. Skip target adding and scanning if we are modifying something about an asset.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${E:A:operation_type}", "op": "==", "right": "MODIFY" }], "next": "verifyEAsforPostingAsset" } }, { "name": "verifyAddToTargetGroupEA", "comment": "Verify TNBL_IO_Sync is true. Otherwise we can't add it to the Target Group nor scan it.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Sync}{value}}", "op": "==", "right": "true" }], "else_next": "verifyEAsforPostingAsset" } }, { "name": "getTargetGroups", "comment": "Get all Target Groups.", "operation": "GET", "parse": "JSON", "transport": { "path": "target-groups" } }, { "name": "setLocalTargetGroupList", "comment": "Set list of target_groups to a local.", "operation": "NOP", "body": "${XC:COPY:{L:TargetGroups}:{P:target_groups}" }, { "name": "isEmptyTargetGroupList", "comment": "[START TARGET GROUP LOOP] Check if we are out of target groups to check.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:L:TargetGroups}", "op": "==", "right": "0" }], "stop": true } }, { "name": "getNextTargetGroup", "comment": "[TARGET GROUP LOOP] Pop top of TargetGroups.", "operation": "VARIABLEOP", "variable_ops": [{ "operation": "POP", "type": "DICTIONARY", "destination": "L:ThisTargetGroup", "source": "L:TargetGroups" }] }, { "name": "verifyCorrectTargetGroup", "comment": "[TARGET GROUP LOOP] Verify the current Target Group matches the EA.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:TNBL_IO_Target_Group}", "op": "==", "right": "${L:A:ThisTargetGroup{name}}" }], "eval": "${XC:COPY:{L:TargetID}:{L:ThisTargetGroup{id}}", "next": "checkExistingTarget" } }, { "name": "loopBackForNextTargetGroup", "comment": "[END TARGET GROUP LOOP] Loop back to check if list is empty.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "0", "op": "==", "right": "0" }], "next": "isEmptyTargetGroupList" } }, { "name": "checkExistingTarget", "comment": "Verify the target doesn't already exist in the Targets list. If it does, no need to add a duplicate.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${L:A:ThisTargetGroup{members}}", "op": "=~", "right": "${L:A:TargetEntry}" }], "next": "verifyEAsforScanning" } }, { "name": "updateTargetList", "comment": "Add item to list of Targets.", "operation": "PUT", "parse": "JSON", "transport": { "path": "target-groups/${L:A:TargetID}" }, "body_list": [ "{", "\"members\": \"${L:A:ThisTargetGroup{members}} ,${L:A:TargetEntry}\"}" ] }, { "name": "verifyEAsforScanning", "comment": "Verify correct EAs to scan item.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Scan_On_Add}{value}}", "op": "==", "right": "true" }, { "left": "${E:A:values{extattrs}{TNBL_IO_Scan_Template}{value}}", "op": "!=", "right": "" } ], "else_next": "verifyEAsforPostingAsset" } }, { "name": "getScans", "comment": "Get list of all scans.", "operation": "GET", "parse": "JSON", "transport": { "path": "scans" } }, { "name": "setLocalScansList", "comment": "Set list of scans to a local.", "operation": "NOP", "body": "${XC:COPY:{L:Scans}:{P:scans}" }, { "name": "isEmptyScanList", "comment": "[START SCAN LOOP] Check if we are out of scans to check.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:L:Scans}", "op": "==", "right": "0" }], "stop": true } }, { "name": "getNextScan", "comment": "[SCAN LOOP] Pop top of Scans.", "operation": "VARIABLEOP", "variable_ops": [{ "operation": "POP", "type": "DICTIONARY", "destination": "L:ThisScan", "source": "L:Scans" }] }, { "name": "verifyCorrectScan", "comment": "[END SCAN LOOP] Verify the current Scan matches the EA.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:TNBL_IO_Scan_Template}", "op": "!=", "right": "${L:A:ThisScan{name}}" }], "next": "isEmptyScanList", "else_eval": "${XC:COPY:{L:Scan_ID}:{L:ThisScan{id}}" } }, { "name": "copyScan", "comment": "Create copy of scan.", "operation": "POST", "parse": "JSON", "transport": { "path": "scans/${L:A:Scan_ID}/copy" } }, { "name": "configureCopiedScan", "comment": "Add some data for scan.", "operation": "PUT", "parse": "JSON", "transport": { "path": "scans/${P:A:id}/" }, "body_list": [ "{", "\"scan_id\":\"${P:A:id}\",", "\"settings\":{", "\"name\":\"Infoblox Scan for ${L:A:TargetEntry} on ${UT:A:TIME}\",", "\"description\": \"Scan occured because of a ${E:A:event_type} event\",", "\"enabled\":\"false\",", "\"text_targets\":\"${L:A:TargetEntry}\"", "}", "}" ] }, { "name": "launchCopyScan", "comment": "Launch scan.", "operation": "POST", "parse": "JSON", "transport": { "path": "scans/${P:A:id}/launch" } }, { "name": "updateLastScanTimestamp", "comment": "Update TNBL_IO_Last_Scan of item with timestamp.", "operation": "PUT", "wapi": "v2.7", "wapi_quoting": "JSON", "transport": { "path": "${L:A:Obj_ref}" }, "body_list": [ "{\"extattrs+\":{\"TNBL_IO_Last_Scan\": { \"value\": \"${E:A:timestamp}\"}}}" ] }, { "name": "verifyEAsforPostingAsset", "comment": "Verify EAs for posting asset.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "==", "right": "true" }], "else_stop": true } }, { "name": "postAssetWithSingleIP", "comment": "Add asset with a single IP (as usual).", "operation": "POST", "parse": "JSON", "transport": { "path": "import/assets" }, "body_list": ["{", "\"assets\": [{\"${L:A:IPvTypeForAssets}\": [\"${L:A:ThisIP}\"], \"mac_address\": [\"${L:A:mac_address}\"],\"netbios_name\": \"${L:A:netbios_name}\",\"operating_system\": [\"${L:A:operating_system}\"]}], \"source\": \"${L:A:source}\"", "}" ] }, { "name": "isEmptyObj_ref", "comment": "Only when the Obj_ref is not empty (something exists there) should we update its timestamp.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:Obj_ref}", "op": "!=", "right": "" }], "else_stop": true } }, { "name": "updateAddAssetTimestamp", "comment": "Update TNBL_IO_Sync_Time of item with timestamp.", "operation": "PUT", "wapi": "v2.9", "wapi_quoting": "JSON", "transport": { "path": "${L:A:Obj_ref}" }, "body_list": [ "{\"extattrs+\":{\"TNBL_IO_Sync_Time\": { \"value\": \"${E:A:timestamp}\"}}}" ] }, { "name": "haltTemplate", "comment": "Halt template.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "1", "op": "==", "right": "1" }], "stop": true } }, { "name": "deleteAsset", "comment": "Delete asset using its netbios_name. TenableIO will return code 202.", "operation": "POST", "parse": "JSON", "transport": { "path": "/api/v2/assets/bulk-jobs/delete" }, "result": [{ "codes": "200,202", "next": "haltTemplate3" }], "body_list": [ "{", "\"query\": {", "\"field\": \"netbios_name\",", "\"operator\": \"eq\",", "\"value\": \"${L:A:netbios_name}\"", "},", "\"hard_delete\": true", "}" ] }, { "name": "haltTemplate3", "comment": "Halt template.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "1", "op": "==", "right": "1" }], "stop": true } } ] }