Refresh Token: Used to generate short-lived access tokens without user interaction.
2. Fetch Existing Incidents from IBM SOAR
- Purpose: Retrieve current incidents to determine the latest synced incident ID.
INCIDENT_URL = "https://9.30.57.77/rest/orgs/201/incidents"
headers = {'Authorization': 'Basic NGVkMTBiZjAtZjU1MS00MTE5LWI0YzQtN2ViZDBjNThiOTBi...'}
incident_list = requests.request("GET", url=INCIDENT_URL, headers=headers, verify=False)
3. Query ManageEngine for New Requests
Purpose: Fetch unresolved incidents from ManageEngine filtered by the latest IBM SOAR incident ID.
list_info = {
"list_info": {
"row_count": 10,
"filter_by": {"id": "17028000000026038"},
"search_criteria": {
"field": "display_id",
"condition": "greater than",
"value": json.loads(incident_list.text)[0]['external_id']
}
}
}
params = {"input_data": json.dumps(list_info)}
request_list = requests.get(ME_REQUEST_URL, headers=ME_headers, params=params, verify=False)
4. Create Incidents in IBM SOAR
Purpose: Loop through ManageEngine requests and create corresponding incidents in SOAR.
for request_to_add in json.loads(request_list.text)['requests']:
payload = json.dumps({
"external_id": request_to_add["display_id"],
"name": request_to_add["subject"],
"discovered_date": int(request_to_add["created_time"]["value"]),
"properties": {"manage_engine_id": int(request_to_add["display_id"])}
})
incident_added = requests.post(INCIDENT_URL, headers=headers, data=payload, verify=False)
5. Error Handling
Purpose: Gracefully handle exceptions to avoid script failure.
try:
# ... code ...
except Exception as e:
print("CLIENT ERROR: {0}\n".format(e))
Best Practices
-
Security:
-
Scheduling:
-
Enhancements:
Full Code with Comments
import requests
import json
def main():
try:
# Step 1: Authenticate with ManageEngine
ME_TOKEN_URL = "https://accounts.zoho.in/oauth/v2/token?refresh_token=1000.005fce...&grant_type=refresh_token"
response = requests.post(ME_TOKEN_URL, verify=False)
access_token = json.loads(response.text)["access_token"]
# Step 2: Configure ManageEngine API headers
ME_headers = {
"Accept": "application/vnd.manageengine.v3+json",
"Authorization": "Zoho-oauthtoken " + access_token
}
# Step 3: Fetch latest incidents from IBM SOAR
INCIDENT_URL = "https://9.30.57.XX/rest/orgs/201/incidents"
soar_headers = {'Authorization': 'Basic NGVkMTBiZjAtZjU1MS00MTE5LWI0YzQtN2ViZDBjNThiOTBi...'}
incident_list = requests.get(INCIDENT_URL, headers=soar_headers, verify=False)
# Step 4: Fetch new requests from ManageEngine
list_info = {
"list_info": {
"search_criteria": {
"field": "display_id",
"condition": "greater than",
"value": json.loads(incident_list.text)[0]['external_id']
}
}
}
params = {"input_data": json.dumps(list_info)}
request_list = requests.get("https://sdpondemand.manageengine.in/api/v3/requests",
headers=ME_headers, params=params, verify=False)
# Step 5: Sync to IBM SOAR
if request_list.json().get('requests'):
for req in request_list.json()['requests']:
payload = json.dumps({
"external_id": req["display_id"],
"name": req["subject"],
"discovered_date": int(req["created_time"]["value"]),
"properties": {"manage_engine_id": req["display_id"]}
})
requests.post(INCIDENT_URL, headers=soar_headers, data=payload, verify=False)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
below images are from ManageEngine ITSM and IBM SOAR where ID 37 is synced with IBM SOAR.
Conclusion
This script automates one-way incident syncing from ManageEngine ITSM to IBM SOAR. By understanding API interactions and security practices, you can extend this to handle bidirectional syncs, attachments, or custom fields. Always test in a non-production environment before deployment.
Reach out to us if you need further guidance. Let’s elevate your security operations together!
Honey Gidwani honey.gidwani@ibm.com
Anuj Shrivastava - ashrivastava@in.ibm.com