Start task sample
- Last Updated: June 30, 2026
- 4 minute read
- Automate MFT
- Documentation
The following Python sample demonstrates how to authenticate with the Automate MFT API and start a task using the Tasks endpoint.
The sample includes JWT authentication, OAuth token retrieval, task execution, retry handling, and task-run status monitoring. This sample can be adapted for use in automation workflows and custom integrations.
Usage examples
python automate-mft-api-calls.py <environment> <tenant_id> <path_to_private_key_file> <kid> [task_id]
Call the licenses endpoint
To call the licenses endpoint in the US environment,
run:
python automate-mft-api-calls.py us <tenant_id> <path_to_private_key_file> <kid>Start a task and monitor its status
To start a task and then check its status, include the optional
task_id:python automate-mft-api-calls.py us <tenant_id> <path_to_private_key_file> <kid> <task_id>Full sample script
import jwt
import time
import uuid
import sys
import requests
import json
# Mandatory information required:
# - environment - "us" or "eu" (provided as first argument)
# - tenant_id - The Tenant ID in the UI
# - private key file path
# - kid - The Public Key ID in the UI
#
# Order of steps:
# 1. Create JWT token
# 2. Get OAuth access token using JWT client assertion (signed JWT token with the private key)
# 3. Call APIs with the access token
def get_base_url(environment):
"""
Get the base URL for the API based on the environment
Args:
environment (str): The environment - "us" or "eu"
Returns:
str: The base URL
"""
env_lower = environment.lower()
if env_lower in ["us", "eu"]:
return f"https://api.{env_lower}.mft.progress.com"
elif env_lower == "staging":
return "https://api.staging.mft.progress.com"
else:
print(f"Error: Invalid environment '{environment}'. Must be 'us', 'eu', or 'staging'", file=sys.stderr)
sys.exit(1)
def retry_on_429(func, *args, **kwargs):
"""
Retry a function if it returns 429 (Too Many Requests)
Args:
func: The function to call
*args: Arguments to pass to the function
**kwargs: Keyword arguments to pass to the function
Returns:
The result of the function call
"""
max_retries = 3
retry_count = 0
while retry_count < max_retries:
try:
return func(*args, **kwargs)
except requests.exceptions.HTTPError as error:
if error.response.status_code == 429:
retry_count += 1
if retry_count < max_retries:
print(f"Received 429, retrying in 5 seconds... (attempt {retry_count}/{max_retries})")
time.sleep(5)
else:
print(f"Max retries reached for 429", file=sys.stderr)
raise
else:
raise
def create_jwt_token(private_key, kid, tenant_id, base_url):
"""
Create a JWT token for authentication
Args:
private_key (str): The private key content
kid (str): The key ID
tenant_id (str): The tenant ID
base_url (str): The base URL for the API
Returns:
str: The JWT token
"""
now = int(time.time())
token = jwt.encode(
{
"aud": f"{base_url}/v1/oauth/token", # Audience - the token endpoint - must be included
"jti": str(uuid.uuid4()), # Unique identifier for the token NOT MANDATORY but recommended
"iat": now, # Issued at time, NOT MANDATORY but recommended
"nbf": now, # Not before time, NOT MANDATORY but recommended
"exp": now + 240, # Expiration time, mandatory, ensure it is short-lived
"iss": tenant_id, # Issuer - The Tenant ID, mandatory
"sub": tenant_id # Subject - The Tenant ID, mandatory
},
private_key,
algorithm="ES256",
headers={"kid": kid}
)
return token
def get_access_token(token, base_url):
"""
Get OAuth access token using JWT client assertion
Args:
token (str): The JWT token
base_url (str): The base URL for the API
Returns:
str: The access token
"""
response = requests.post(
f"{base_url}/v1/oauth/token",
headers={
"Content-Type": "application/json"
},
json={
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": token
},
timeout=10
)
response.raise_for_status()
return response.json()["access_token"]
def get_current_licenses(access_token, base_url):
"""
Get current licenses
Args:
access_token (str): The OAuth access token
base_url (str): The base URL for the API
Returns:
dict: The licenses data
"""
def _get_licenses():
response = requests.get(
f"{base_url}/v1/licenses/current",
headers={
"Authorization": f"bearer {access_token}"
}
)
response.raise_for_status()
return response.json()
return retry_on_429(_get_licenses)
def start_task(access_token, task_id, base_url):
"""
Start a task
Args:
access_token (str): The OAuth access token
task_id (str): The task ID
base_url (str): The base URL for the API
Returns:
dict: The task start response
"""
def _start_task():
response = requests.post(
f"{base_url}/v1/tasks/{task_id}/start",
headers={
"Authorization": f"bearer {access_token}"
},
json={}
)
response.raise_for_status()
return response.json()
return retry_on_429(_start_task)
def get_task_run(access_token, task_run_id, base_url):
"""
Get task run status
Args:
access_token (str): The OAuth access token
task_run_id (str): The task run ID
base_url (str): The base URL for the API
Returns:
dict: The task run data
"""
def _get_task_run():
response = requests.get(
f"{base_url}/v1/task-runs/{task_run_id}",
headers={
"Authorization": f"bearer {access_token}"
}
)
response.raise_for_status()
return response.json()
return retry_on_429(_get_task_run)
def call_apis(environment, tenant_id, private_key_file, kid, task_id=None):
"""
Main function to call APIs
Args:
environment (str): The environment - "us" or "eu"
tenant_id (str): The Tenant ID
private_key_file (str): Path to the private key file
kid (str): The Public Key ID in the UI
task_id (str, optional): The task ID - currently can be taken from the URL when a task is selected in the tasks page
"""
try:
# Get base URL from environment
base_url = get_base_url(environment)
# Read the private key
with open(private_key_file, "r", encoding="utf-8") as f:
private_key = f.read()
# Create JWT token
token = create_jwt_token(private_key, kid, tenant_id, base_url)
# Get access token
access_token = get_access_token(token, base_url)
# Call the licenses API
licenses_data = get_current_licenses(access_token, base_url)
print("Licenses data:", json.dumps(licenses_data, indent=2))
if not task_id:
return
# Start a task (example task_id: '02115928-16fe-4493-949b-d77d302a88ee')
start_task_id = start_task(access_token, task_id, base_url)
print("Started Task:", json.dumps(start_task_id, indent=2))
task_run_status = ""
task_run_data = None
while task_run_status not in ["success", "failed"]:
try:
task_run_data = get_task_run(access_token, start_task_id["id"], base_url)
task_run_status = task_run_data.get("status", {}).get("taskRunStatus", "")
print(f"Task Run Status: {task_run_status}")
# Sleep for 5 seconds before checking again
time.sleep(5)
except requests.exceptions.HTTPError as error:
if error.response.status_code == 403:
print("Received 403, refreshing access token...")
# Refresh the access token
token = create_jwt_token(private_key, kid, tenant_id, base_url)
access_token = get_access_token(token, base_url)
print("Access token refreshed, retrying...")
else:
raise
print("Task Completed:", json.dumps(task_run_data, indent=2))
except requests.exceptions.RequestException as error:
if hasattr(error, 'response') and error.response is not None:
print(f"API Error: {error.response.status_code}", file=sys.stderr)
try:
print(error.response.json(), file=sys.stderr)
except:
print(error.response.text, file=sys.stderr)
else:
print(f"Error: {str(error)}", file=sys.stderr)
sys.exit(1)
except Exception as error:
print(f"Error: {str(error)}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
args = sys.argv[1:]
if len(args) < 4:
print("Usage: python automate-mft-api-calls.py <environment> <tenant_id> <private_key_file> <kid> [task_id]", file=sys.stderr)
print(" environment: 'us', 'eu', or 'staging'", file=sys.stderr)
sys.exit(1)
environment = args[0]
tenant_id = args[1]
private_key_file = args[2]
kid = args[3]
task_id = args[4] if len(args) > 4 else None
call_apis(environment, tenant_id, private_key_file, kid, task_id)