Appearance
Situate REST API Reference for Automation
This document provides a comprehensive reference for automating Situate workflows via the REST API. It is designed for use with AI coding assistants like Claude Code to generate Python scripts.
Connection Setup
Base URL
https://<server>/situateAuthentication
All requests require an API key passed in the X-API-Key header.
python
import requests
BASE_URL = "https://<server>/situate"
API_KEY = "your-api-key-here"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
}
# For XML responses
headers_xml = {
"X-API-Key": API_KEY,
"Content-Type": "application/xml",
"Accept": "application/xml"
}
# Disable SSL warnings for self-signed certs (development only)
requests.packages.urllib3.disable_warnings()Workflows
List All Workflows
python
def list_workflows(state=None, queue=None):
"""
List all workflows, optionally filtered by state and queue.
Args:
state: 'submitted' or 'approved'
queue: queue name (default: all)
Returns:
List of workflow objects
"""
params = {}
if state:
params['state'] = state
if queue:
params['queue'] = queue
response = requests.get(
f"{BASE_URL}/workflows",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()
return response.json()
def find_workflow_by_group_and_name(group_path, workflow_name, state="approved"):
"""
Find a workflow ID by its group path and name.
Workflows are organized in a group hierarchy like a filesystem.
This function finds a workflow given its logical location.
Args:
group_path: Group path like "a/b/c" or "Production/Daily Jobs"
workflow_name: Name of the workflow
state: 'submitted' or 'approved' (default: approved)
Returns:
Workflow ID string, or None if not found
Example:
workflow_id = find_workflow_by_group_and_name(
"Production/Batch/Nightly",
"DataBackup"
)
"""
result = list_workflows(state=state)
# Normalize group path (remove leading/trailing slashes)
group_path = group_path.strip('/')
workflows = result.get('workflows', [])
for wf in workflows:
attrs = wf.get('attrs', {})
wf_name = attrs.get('name')
wf_group = attrs.get('groupPath', '').strip('/')
if wf_name == workflow_name and wf_group == group_path:
return attrs.get('id')
return None
def get_workflow_by_group_and_name(group_path, workflow_name, state="approved", format="xml"):
"""
Get a workflow by its group path and name.
Args:
group_path: Group path like "a/b/c"
workflow_name: Name of the workflow
state: 'submitted' or 'approved'
format: 'json' or 'xml' (default: xml for schedule modification)
Returns:
Workflow XML document (default) or JSON object
Raises:
ValueError: If workflow not found
Note:
Use format='xml' (default) when you need to modify schedules or
other workflow internals. JSON is useful for reading metadata only.
"""
workflow_id = find_workflow_by_group_and_name(group_path, workflow_name, state)
if not workflow_id:
raise ValueError(f"Workflow '{workflow_name}' not found in group '{group_path}'")
return get_workflow(workflow_id, state=state, format=format)Get Workflow by ID
python
def get_workflow(workflow_id, state=None, format="json"):
"""
Retrieve a specific workflow.
Args:
workflow_id: The workflow's unique ID
state: 'submitted' or 'approved'
format: 'json' or 'xml'
Returns:
Workflow object (JSON) or XML document
"""
params = {}
if state:
params['state'] = state
h = headers_xml if format == "xml" else headers
response = requests.get(
f"{BASE_URL}/workflows/{workflow_id}",
headers=h,
params=params,
verify=False
)
response.raise_for_status()
if format == "xml":
return response.text
return response.json()Execute a Workflow
python
def execute_workflow(workflow_id, trigger_name, parameters=None):
"""
Execute a workflow with the specified trigger.
Args:
workflow_id: The workflow's unique ID
trigger_name: Name of the trigger to use
parameters: Dict of parameters to pass to the workflow
Returns:
Execution response
"""
params = {"trigger": trigger_name}
data = parameters or {}
response = requests.post(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers,
params=params,
json=data,
verify=False
)
response.raise_for_status()
return response.json()Create New Workflow
python
def create_workflow(workflow_xml, preserve_acl=False):
"""
Submit a new workflow to Situate.
Args:
workflow_xml: Complete workflow XML document
preserve_acl: If True, preserve ACL (requires admin)
Returns:
Validation response with workflow ID
"""
params = {}
if preserve_acl:
params['preserveAcl'] = 'true'
response = requests.post(
f"{BASE_URL}/workflows",
headers=headers_xml,
params=params,
data=workflow_xml,
verify=False
)
response.raise_for_status()
return response.json()Update Existing Workflow
python
def update_workflow(workflow_id, workflow_xml):
"""
Update an existing workflow. Places workflow in 'submitted' state.
Args:
workflow_id: The workflow's unique ID (must match ID in XML)
workflow_xml: Complete workflow XML document
Returns:
Validation response
"""
response = requests.put(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers_xml,
data=workflow_xml,
verify=False
)
response.raise_for_status()
return response.json()Approve and Enable Workflow
python
def approve_workflow(workflow_id, enable=True):
"""
Approve a submitted workflow and optionally enable it.
Args:
workflow_id: The workflow's unique ID
enable: If True, enable the workflow for execution
Returns:
Approval response
"""
data = {
"approveWorkflow": True,
"enableWorkflow": enable
}
response = requests.patch(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers,
json=data,
verify=False
)
response.raise_for_status()
return response.json()Delete Workflow
python
def delete_workflow(workflow_id, state="approved"):
"""
Delete a workflow.
Args:
workflow_id: The workflow's unique ID
state: 'submitted' or 'approved'
"""
params = {"state": state}
response = requests.delete(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()Complete Workflow Update Cycle
python
def update_and_approve_workflow(workflow_id, workflow_xml):
"""
Complete workflow update: submit changes and approve.
Args:
workflow_id: The workflow's unique ID
workflow_xml: Modified workflow XML
Returns:
Final approval response
"""
# Step 1: Submit the updated workflow
update_response = update_workflow(workflow_id, workflow_xml)
# Check for validation errors
if update_response.get('validationErrors'):
raise Exception(f"Validation errors: {update_response['validationErrors']}")
# Step 2: Approve and enable
return approve_workflow(workflow_id, enable=True)Workflow Triggers
Enable/Disable a Trigger
python
def set_trigger_enabled(workflow_id, trigger_name, enabled=True):
"""
Enable or disable a specific trigger on a workflow.
Args:
workflow_id: The workflow's unique ID
trigger_name: Name of the trigger
enabled: True to enable, False to disable
"""
data = {
"action": "enable",
"enable": enabled
}
response = requests.patch(
f"{BASE_URL}/workflows/{workflow_id}/triggers/{trigger_name}",
headers=headers,
json=data,
verify=False
)
response.raise_for_status()
return response.json()Modify Schedule Trigger (XML Manipulation)
Schedule triggers are embedded in the workflow XML. Situate uses SubSchedule types (not cron expressions).
SubSchedule Types
| Type | Description | Key Properties |
|---|---|---|
DailySubSchedule | Every N days | every, startHour, startMinute, startSecond |
WeeklySubSchedule | Specific days of week | daysMask (boolean[7] Sun-Sat), every (weeks) |
PeriodicSubSchedule | Every N seconds/minutes/hours | every, everyScale (0=hours, 1=minutes, 2=seconds) |
MonthlyDateSubSchedule | Specific dates of months | days (int[]), months (boolean[12]), lastDayOfMonth |
CalendarSubSchedule | Dates from a calendar | calendar (calendar name) |
Repeat Modes (intra-day recurrence)
Each subschedule supports repeating throughout the day:
| repeatMode | Description |
|---|---|
| 0 | No repeat (run once) |
| 1 | Repeat until specific time |
| 2 | Repeat until end of day |
| 3 | Repeat N times |
python
import xml.etree.ElementTree as ET
def modify_daily_schedule_time(workflow_xml, trigger_name, hour, minute, second=0):
"""
Modify a DailySubSchedule trigger's start time.
Args:
workflow_xml: The workflow XML string
trigger_name: Name of the schedule trigger to modify
hour: New start hour (0-23)
minute: New start minute (0-59)
second: New start second (0-59)
Returns:
Modified workflow XML string
"""
root = ET.fromstring(workflow_xml)
# Find triggers and locate by name
for trigger in root.iter('trigger'):
name_elem = trigger.find('name')
if name_elem is not None and name_elem.text == trigger_name:
# Find the DailySubSchedule within includeSchedules
for daily in trigger.iter('com.xona.wf.schedule.DailySubSchedule'):
start_hour = daily.find('startHour')
start_minute = daily.find('startMinute')
start_second = daily.find('startSecond')
if start_hour is not None:
start_hour.text = str(hour)
if start_minute is not None:
start_minute.text = str(minute)
if start_second is not None:
start_second.text = str(second)
break
return ET.tostring(root, encoding='unicode')
def modify_weekly_schedule(workflow_xml, trigger_name, days_of_week, hour, minute):
"""
Modify a WeeklySubSchedule trigger.
Args:
workflow_xml: The workflow XML string
trigger_name: Name of the schedule trigger
days_of_week: List of day names ('sunday', 'monday', etc.) or indices (0=Sun, 6=Sat)
hour: Start hour (0-23)
minute: Start minute (0-59)
Returns:
Modified workflow XML string
"""
# Convert day names to indices
day_names = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
day_indices = []
for day in days_of_week:
if isinstance(day, str):
day_indices.append(day_names.index(day.lower()))
else:
day_indices.append(day)
root = ET.fromstring(workflow_xml)
for trigger in root.iter('trigger'):
name_elem = trigger.find('name')
if name_elem is not None and name_elem.text == trigger_name:
for weekly in trigger.iter('com.xona.wf.schedule.WeeklySubSchedule'):
# Update time
start_hour = weekly.find('startHour')
start_minute = weekly.find('startMinute')
if start_hour is not None:
start_hour.text = str(hour)
if start_minute is not None:
start_minute.text = str(minute)
# Update days mask
days_mask = weekly.find('daysMask')
if days_mask is not None:
# Clear existing and rebuild
days_mask.clear()
for i in range(7):
bool_elem = ET.SubElement(days_mask, 'boolean')
bool_elem.text = 'true' if i in day_indices else 'false'
break
return ET.tostring(root, encoding='unicode')
def update_workflow_schedule(workflow_id, trigger_name, hour, minute):
"""
Complete process to update a workflow's schedule trigger time.
Args:
workflow_id: The workflow's unique ID
trigger_name: Name of the schedule trigger
hour: New start hour
minute: New start minute
"""
# Step 1: Get the workflow XML
workflow_xml = get_workflow(workflow_id, format="xml")
# Step 2: Modify the schedule
modified_xml = modify_daily_schedule_time(workflow_xml, trigger_name, hour, minute)
# Step 3: Update and approve
return update_and_approve_workflow(workflow_id, modified_xml)Workflow Instances (Running Workflows)
List Running Instances
python
def list_workflow_instances(state=None, queue=None):
"""
List workflow instances.
Args:
state: 'running', 'canceling', or 'unconfirmed'
queue: queue name
Returns:
List of workflow instances
"""
params = {}
if state:
params['state'] = state
if queue:
params['queue'] = queue
response = requests.get(
f"{BASE_URL}/workflowInstances",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()
return response.json()Cancel a Running Workflow
python
def cancel_workflow_instance(instance_id):
"""
Cancel a running workflow instance.
Args:
instance_id: The instance's unique ID
"""
response = requests.put(
f"{BASE_URL}/workflowInstances/{instance_id}",
headers=headers,
verify=False
)
response.raise_for_status()Workflow Logs
Query Workflow Logs
python
def get_workflow_logs(query_type="today"):
"""
Get workflow execution logs.
Args:
query_type: Time period filter
- 'today': Today
- 'yesterday': Yesterday
- 'L1': Last 1 hour
- 'L4': Last 4 hours
- 'L8': Last 8 hours
- 'L12': Last 12 hours
- 'L24': Last 24 hours
- 'L48': Last 48 hours
- 'LW': Last week
- 'LM': Last month
- 'L60': Last 60 days
Returns:
List of workflow log entries
"""
params = {"queryType": query_type}
response = requests.get(
f"{BASE_URL}/workflowLogs",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()
return response.json()Get Specific Workflow Instance Log
python
def get_workflow_instance_log(workflow_id, instance_id, start=0):
"""
Get detailed log entries for a specific workflow execution.
Args:
workflow_id: The workflow's unique ID
instance_id: The instance's unique ID
start: Offset index for pagination
Returns:
List of log entries
"""
params = {"start": start}
response = requests.get(
f"{BASE_URL}/workflowLogs/{workflow_id}/{instance_id}",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()
return response.json()Workflow Groups
List Groups
python
def list_workflow_groups():
"""List all workflow groups."""
response = requests.get(
f"{BASE_URL}/workflowGroups",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Create Group
python
def create_workflow_group(name, description=None, parent_id=None):
"""
Create a new workflow group.
Args:
name: Group name
description: Optional description
parent_id: Parent group ID (None for root)
"""
data = {"name": name}
if description:
data["description"] = description
if parent_id:
data["parentId"] = parent_id
response = requests.post(
f"{BASE_URL}/workflowGroups",
headers=headers,
json=data,
verify=False
)
response.raise_for_status()
return response.json()Workflow Queues
List Queues
python
def list_workflow_queues():
"""List all workflow queues."""
response = requests.get(
f"{BASE_URL}/workflowQueues",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Pause/Resume Queue
python
def set_queue_paused(queue_name, paused=True):
"""
Pause or resume a workflow queue.
Args:
queue_name: Name of the queue (e.g., 'Master')
paused: True to pause, False to resume
"""
data = {"paused": paused}
response = requests.patch(
f"{BASE_URL}/workflowQueues/{queue_name}",
headers=headers,
json=data,
verify=False
)
response.raise_for_status()
return response.json()Assets
List Assets
python
def list_assets(group_name=None, group_id=None):
"""
List all assets (agents).
Args:
group_name: Filter by group name (e.g., 'dev/chicago')
group_id: Filter by group ID
Returns:
List of asset objects
"""
params = {}
if group_name:
params['groupName'] = group_name
if group_id:
params['groupId'] = group_id
response = requests.get(
f"{BASE_URL}/assets",
headers=headers,
params=params,
verify=False
)
response.raise_for_status()
return response.json()Get Asset by ID
python
def get_asset(asset_id):
"""Get a specific asset by ID."""
response = requests.get(
f"{BASE_URL}/assets/{asset_id}",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Calendars
List Calendars
python
def list_calendars():
"""List all calendars."""
response = requests.get(
f"{BASE_URL}/calendars",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Update Calendar
python
def update_calendar(calendar_id, calendar_data):
"""
Update a calendar.
Args:
calendar_id: The calendar's unique ID
calendar_data: TraditionalCalendar JSON object
"""
response = requests.put(
f"{BASE_URL}/calendars/{calendar_id}",
headers=headers,
json=calendar_data,
verify=False
)
response.raise_for_status()
return response.json()System
Get System Statistics
python
def get_system_statistics():
"""
Get system statistics including:
- active: Number of active workflows
- approved: Number of approved workflows
- assets: Number of registered assets
- executed: Workflows executed since startup
- version: Situate server version
"""
response = requests.get(
f"{BASE_URL}/system/statistics",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Get Situate Properties
python
def get_situate_properties():
"""Get the server's situate.properties configuration."""
response = requests.get(
f"{BASE_URL}/system/situate-properties",
headers=headers,
verify=False
)
response.raise_for_status()
return response.json()Complete Example: Update a Schedule Trigger
This example demonstrates the full process of modifying a workflow's schedule using group path and workflow name (not hardcoded IDs):
python
#!/usr/bin/env python3
"""
Example: Update a workflow's schedule trigger to run at a new time.
Finds the workflow by group path and name.
"""
import requests
import xml.etree.ElementTree as ET
# Configuration
BASE_URL = "https://situate.example.com/situate"
API_KEY = "your-api-key"
# Identify workflow by group and name (not hardcoded ID)
GROUP_PATH = "Production/Batch/Nightly"
WORKFLOW_NAME = "DataBackup"
TRIGGER_NAME = "DailySchedule"
NEW_HOUR = 9
NEW_MINUTE = 0
headers_json = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
}
headers_xml = {
"X-API-Key": API_KEY,
"Content-Type": "application/xml",
"Accept": "application/xml"
}
def find_workflow_id(group_path, workflow_name):
"""Find workflow ID by group path and name."""
response = requests.get(
f"{BASE_URL}/workflows",
headers=headers_json,
params={"state": "approved"},
verify=False
)
response.raise_for_status()
group_path = group_path.strip('/')
for wf in response.json().get('workflows', []):
attrs = wf.get('attrs', {})
if (attrs.get('name') == workflow_name and
attrs.get('groupPath', '').strip('/') == group_path):
return attrs.get('id')
return None
def main():
# Step 1: Find the workflow ID by group and name
print(f"Finding workflow '{WORKFLOW_NAME}' in group '{GROUP_PATH}'...")
workflow_id = find_workflow_id(GROUP_PATH, WORKFLOW_NAME)
if not workflow_id:
print(f" ERROR: Workflow not found!")
return
print(f" Found workflow ID: {workflow_id}")
# Step 2: Get the workflow XML
print("Fetching workflow XML...")
response = requests.get(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers_xml,
verify=False
)
response.raise_for_status()
workflow_xml = response.text
# Step 3: Parse and modify the XML
print(f"Updating trigger '{TRIGGER_NAME}' to {NEW_HOUR:02d}:{NEW_MINUTE:02d}")
root = ET.fromstring(workflow_xml)
# Find the trigger by name and update the subschedule
for trigger in root.iter('trigger'):
name_elem = trigger.find('name')
if name_elem is not None and name_elem.text == TRIGGER_NAME:
# Look for DailySubSchedule (or other subschedule types)
for subschedule in trigger.iter('com.xona.wf.schedule.DailySubSchedule'):
start_hour = subschedule.find('startHour')
start_minute = subschedule.find('startMinute')
if start_hour is not None:
print(f" Old time: {start_hour.text}:{start_minute.text if start_minute is not None else '00'}")
start_hour.text = str(NEW_HOUR)
if start_minute is not None:
start_minute.text = str(NEW_MINUTE)
print(f" New time: {NEW_HOUR:02d}:{NEW_MINUTE:02d}")
break
modified_xml = ET.tostring(root, encoding='unicode')
# Step 4: Submit the updated workflow
print("Submitting updated workflow...")
response = requests.put(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers_xml,
data=modified_xml,
verify=False
)
response.raise_for_status()
print(" Workflow submitted successfully")
# Step 5: Approve and enable
print("Approving workflow...")
response = requests.patch(
f"{BASE_URL}/workflows/{workflow_id}",
headers=headers_json,
json={"approveWorkflow": True, "enableWorkflow": True},
verify=False
)
response.raise_for_status()
print(" Workflow approved and enabled")
print("Done!")
if __name__ == "__main__":
main()Error Handling
Common HTTP status codes:
| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created (workflow submitted/approved) |
| 400 | Bad Request (invalid data, validation errors) |
| 401 | Unauthorized (invalid/missing API key) |
| 403 | Forbidden (license issue, permission denied) |
| 404 | Not Found (workflow/resource doesn't exist) |
| 500 | Server Error |
python
def handle_api_error(response):
"""Handle API errors with useful messages."""
if response.status_code == 400:
raise Exception(f"Invalid request: {response.text}")
elif response.status_code == 401:
raise Exception("Authentication failed - check your API key")
elif response.status_code == 403:
raise Exception(f"Permission denied: {response.text}")
elif response.status_code == 404:
raise Exception("Resource not found")
elif response.status_code >= 500:
raise Exception(f"Server error: {response.text}")
response.raise_for_status()Schedule XML Reference
DailySubSchedule Example
Run every day at 8:00 AM:
xml
<com.xona.wf.schedule.DailySubSchedule>
<every>1</every>
<startHour>8</startHour>
<startMinute>0</startMinute>
<startSecond>0</startSecond>
<repeatMode>0</repeatMode>
<from>
<day>1</day>
<month>1</month>
<year>2024</year>
</from>
</com.xona.wf.schedule.DailySubSchedule>WeeklySubSchedule Example
Run Monday through Friday at 9:30 AM:
xml
<com.xona.wf.schedule.WeeklySubSchedule>
<every>1</every>
<startHour>9</startHour>
<startMinute>30</startMinute>
<startSecond>0</startSecond>
<repeatMode>0</repeatMode>
<daysMask>
<boolean>false</boolean> <!-- Sunday -->
<boolean>true</boolean> <!-- Monday -->
<boolean>true</boolean> <!-- Tuesday -->
<boolean>true</boolean> <!-- Wednesday -->
<boolean>true</boolean> <!-- Thursday -->
<boolean>true</boolean> <!-- Friday -->
<boolean>false</boolean> <!-- Saturday -->
</daysMask>
</com.xona.wf.schedule.WeeklySubSchedule>PeriodicSubSchedule Example
Run every 2 hours:
xml
<com.xona.wf.schedule.PeriodicSubSchedule>
<every>2</every>
<everyScale>0</everyScale> <!-- 0=hours, 1=minutes, 2=seconds -->
<repeatMode>0</repeatMode>
</com.xona.wf.schedule.PeriodicSubSchedule>MonthlyDateSubSchedule Example
Run on the 1st and 15th of every month at midnight:
xml
<com.xona.wf.schedule.MonthlyDateSubSchedule>
<startHour>0</startHour>
<startMinute>0</startMinute>
<startSecond>0</startSecond>
<repeatMode>0</repeatMode>
<days>
<int>1</int>
<int>15</int>
</days>
<months>
<boolean>true</boolean> <!-- January -->
<boolean>true</boolean> <!-- February -->
<boolean>true</boolean> <!-- March -->
<boolean>true</boolean> <!-- April -->
<boolean>true</boolean> <!-- May -->
<boolean>true</boolean> <!-- June -->
<boolean>true</boolean> <!-- July -->
<boolean>true</boolean> <!-- August -->
<boolean>true</boolean> <!-- September -->
<boolean>true</boolean> <!-- October -->
<boolean>true</boolean> <!-- November -->
<boolean>true</boolean> <!-- December -->
</months>
<lastDayOfMonth>false</lastDayOfMonth>
</com.xona.wf.schedule.MonthlyDateSubSchedule>CalendarSubSchedule Example
Run on dates defined in "BusinessHolidays" calendar:
xml
<com.xona.wf.schedule.CalendarSubSchedule>
<startHour>6</startHour>
<startMinute>0</startMinute>
<startSecond>0</startSecond>
<repeatMode>0</repeatMode>
<calendar>BusinessHolidays</calendar>
</com.xona.wf.schedule.CalendarSubSchedule>Repeat Mode Example
Daily at 9:00 AM, repeat every 30 minutes until 5:00 PM:
xml
<com.xona.wf.schedule.DailySubSchedule>
<every>1</every>
<startHour>9</startHour>
<startMinute>0</startMinute>
<startSecond>0</startSecond>
<repeatMode>1</repeatMode> <!-- 1 = repeat until time -->
<repeatEvery>30</repeatEvery>
<repeatEveryScale>1</repeatEveryScale> <!-- 1 = minutes -->
<repeatHour>17</repeatHour>
<repeatMinute>0</repeatMinute>
<repeatSecond>0</repeatSecond>
</com.xona.wf.schedule.DailySubSchedule>Complete Schedule Trigger Structure
xml
<trigger class="com.xona.wf.trigger.ScheduleTrigger">
<name>MyScheduleTrigger</name>
<triggerConfig class="com.xona.wf.config.ScheduleTriggerConfigObject">
<schedule>
<includeSchedules>
<!-- One or more SubSchedule elements -->
</includeSchedules>
<excludeSchedules>
<!-- Optional: SubSchedules that block execution -->
</excludeSchedules>
<timeZoneID>America/Chicago</timeZoneID>
<preventConcurrency>true</preventConcurrency>
</schedule>
</triggerConfig>
</trigger>