Overview
Any orchestration tool that can make REST API calls can integrate with Validatar. This guide provides complete, copy-paste-ready scripts in Python, PowerShell, and Bash for the execute-poll-evaluate pattern. Adapt these for your specific orchestrator.
Prerequisites
- Validatar API token with the Execution scope enabled — see User Tokens
- Network access from your orchestration environment to the Validatar API endpoint
- Your Validatar project ID and job ID (visible in the Validatar UI URL)
Example: Execute a Job and Evaluate Results (Python)
import requests
import time
import os
import sys
# ---------------------------------------------------------------------------
# Configuration — set these as environment variables or replace inline
# ---------------------------------------------------------------------------
VALIDATAR_API_URL = os.environ.get("VALIDATAR_API_URL") # e.g., https://mycompany.cloud.validatar.com
VALIDATAR_API_TOKEN = os.environ.get("VALIDATAR_API_TOKEN")
PROJECT_ID = int(os.environ.get("VALIDATAR_PROJECT_ID", "0"))
JOB_ID = int(os.environ.get("VALIDATAR_JOB_ID", "0"))
POLL_INTERVAL_SECONDS = 5
TIMEOUT_SECONDS = int(os.environ.get("VALIDATAR_TIMEOUT", "1800")) # 30 minutes default
HEADERS = {
"x-val-api-token": VALIDATAR_API_TOKEN,
"Content-Type": "application/json"
}
BASE = f"{VALIDATAR_API_URL}/core/api/v1"
# ---------------------------------------------------------------------------
# Step 1 — Execute the job
# ---------------------------------------------------------------------------
print(f"Executing job {JOB_ID} in project {PROJECT_ID}...")
execute_url = f"{BASE}/projects/{PROJECT_ID}/jobs/{JOB_ID}/execute"
response = requests.post(execute_url, headers=HEADERS)
response.raise_for_status()
execution = response.json()
batch_key = execution["executionKey"]
print(f"Execution started. Batch key: {batch_key}")
# ---------------------------------------------------------------------------
# Step 2 — Poll for results
# ---------------------------------------------------------------------------
results_url = f"{BASE}/projects/{PROJECT_ID}/jobs/{JOB_ID}/results/{batch_key}"
elapsed = 0
while elapsed < TIMEOUT_SECONDS:
time.sleep(POLL_INTERVAL_SECONDS)
elapsed += POLL_INTERVAL_SECONDS
poll_response = requests.get(results_url, headers=HEADERS)
poll_response.raise_for_status()
result = poll_response.json()
status = result.get("status", "Unknown")
print(f" [{elapsed}s] Status: {status}")
if status in ("Completed", "Aborted", "Abandoned"):
break
else:
print(f"ERROR: Timeout after {TIMEOUT_SECONDS} seconds. Job may still be running.")
sys.exit(1)
# ---------------------------------------------------------------------------
# Step 3 — Evaluate results
# ---------------------------------------------------------------------------
print(f"\nJob finished with status: {status}")
print(f" Started: {result.get('dateStarted')}")
print(f" Completed: {result.get('dateCompleted')}")
if status != "Completed":
print(f"FAILED: Job ended with status '{status}'.")
sys.exit(1)
# Check individual test results within the job
tests = result.get("tests", [])
failed_tests = [t for t in tests if t.get("status") not in ("Passed", "Completed")]
if failed_tests:
print(f"\n{len(failed_tests)} test(s) did not pass:")
for t in failed_tests:
print(f" - {t.get('name')} (ID: {t.get('id')}): {t.get('status')}")
sys.exit(1)
print(f"All {len(tests)} test(s) passed. Pipeline may continue.")
sys.exit(0)
Example: Execute a Job and Evaluate Results (PowerShell)
# ---------------------------------------------------------------------------
# Configuration — set these as environment variables or replace inline
# ---------------------------------------------------------------------------
$ValidatarApiUrl = $env:VALIDATAR_API_URL # e.g., https://mycompany.cloud.validatar.com
$ValidatarApiToken = $env:VALIDATAR_API_TOKEN
$ProjectId = [int]$env:VALIDATAR_PROJECT_ID
$JobId = [int]$env:VALIDATAR_JOB_ID
$PollIntervalSeconds = 5
$TimeoutSeconds = if ($env:VALIDATAR_TIMEOUT) { [int]$env:VALIDATAR_TIMEOUT } else { 1800 }
$Headers = @{
"x-val-api-token" = $ValidatarApiToken
"Content-Type" = "application/json"
}
$Base = "$ValidatarApiUrl/core/api/v1"
# ---------------------------------------------------------------------------
# Compatibility — TLS 1.2 for Windows PowerShell 5.1
# ---------------------------------------------------------------------------
if ($PSVersionTable.PSVersion.Major -le 5) {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}
# ---------------------------------------------------------------------------
# Step 1 — Execute the job
# ---------------------------------------------------------------------------
Write-Host "Executing job $JobId in project $ProjectId..."
$ExecuteUrl = "$Base/projects/$ProjectId/jobs/$JobId/execute"
try {
$ExecuteResponse = Invoke-RestMethod -Uri $ExecuteUrl -Method Post -Headers $Headers -ErrorAction Stop
}
catch {
Write-Error "Failed to execute job: $_"
exit 1
}
$BatchKey = $ExecuteResponse.executionKey
Write-Host "Execution started. Batch key: $BatchKey"
# ---------------------------------------------------------------------------
# Step 2 — Poll for results
# ---------------------------------------------------------------------------
$ResultsUrl = "$Base/projects/$ProjectId/jobs/$JobId/results/$BatchKey"
$Elapsed = 0
$Status = "Running"
while ($Elapsed -lt $TimeoutSeconds) {
Start-Sleep -Seconds $PollIntervalSeconds
$Elapsed += $PollIntervalSeconds
try {
$PollResponse = Invoke-RestMethod -Uri $ResultsUrl -Method Get -Headers $Headers -ErrorAction Stop
}
catch {
Write-Warning "Poll request failed at ${Elapsed}s: $_. Retrying..."
continue
}
$Status = $PollResponse.status
Write-Host " [${Elapsed}s] Status: $Status"
if ($Status -in @("Completed", "Aborted", "Abandoned")) {
break
}
}
if ($Elapsed -ge $TimeoutSeconds -and $Status -eq "Running") {
Write-Error "Timeout after $TimeoutSeconds seconds. Job may still be running."
exit 1
}
# ---------------------------------------------------------------------------
# Step 3 — Evaluate results
# ---------------------------------------------------------------------------
Write-Host "`nJob finished with status: $Status"
Write-Host " Started: $($PollResponse.dateStarted)"
Write-Host " Completed: $($PollResponse.dateCompleted)"
if ($Status -ne "Completed") {
Write-Error "Job ended with status '$Status'."
exit 1
}
# Check individual test results within the job
$Tests = $PollResponse.tests
$FailedTests = $Tests | Where-Object { $_.status -notin @("Passed", "Completed") }
if ($FailedTests) {
Write-Host "`n$($FailedTests.Count) test(s) did not pass:"
foreach ($t in $FailedTests) {
Write-Host " - $($t.name) (ID: $($t.id)): $($t.status)"
}
exit 1
}
Write-Host "All $($Tests.Count) test(s) passed. Pipeline may continue."
exit 0
Example: Execute a Job (Bash/curl)
#!/usr/bin/env bash
set -euo pipefail
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
VALIDATAR_API_URL="${VALIDATAR_API_URL:?Set VALIDATAR_API_URL}"
VALIDATAR_API_TOKEN="${VALIDATAR_API_TOKEN:?Set VALIDATAR_API_TOKEN}"
PROJECT_ID="${VALIDATAR_PROJECT_ID:?Set VALIDATAR_PROJECT_ID}"
JOB_ID="${VALIDATAR_JOB_ID:?Set VALIDATAR_JOB_ID}"
POLL_INTERVAL=5
TIMEOUT="${VALIDATAR_TIMEOUT:-1800}"
BASE="${VALIDATAR_API_URL}/core/api/v1"
# ---------------------------------------------------------------------------
# Step 1 — Execute
# ---------------------------------------------------------------------------
echo "Executing job ${JOB_ID} in project ${PROJECT_ID}..."
EXEC_RESPONSE=$(curl -s -f -X POST \
"${BASE}/projects/${PROJECT_ID}/jobs/${JOB_ID}/execute" \
-H "x-val-api-token: ${VALIDATAR_API_TOKEN}" \
-H "Content-Type: application/json")
BATCH_KEY=$(echo "${EXEC_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin)['executionKey'])")
echo "Execution started. Batch key: ${BATCH_KEY}"
# ---------------------------------------------------------------------------
# Step 2 — Poll
# ---------------------------------------------------------------------------
RESULTS_URL="${BASE}/projects/${PROJECT_ID}/jobs/${JOB_ID}/results/${BATCH_KEY}"
ELAPSED=0
STATUS="Running"
while [ "${ELAPSED}" -lt "${TIMEOUT}" ]; do
sleep "${POLL_INTERVAL}"
ELAPSED=$((ELAPSED + POLL_INTERVAL))
POLL_RESPONSE=$(curl -s -f -X GET "${RESULTS_URL}" \
-H "x-val-api-token: ${VALIDATAR_API_TOKEN}")
STATUS=$(echo "${POLL_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','Unknown'))")
echo " [${ELAPSED}s] Status: ${STATUS}"
if [[ "${STATUS}" == "Completed" || "${STATUS}" == "Aborted" || "${STATUS}" == "Abandoned" ]]; then
break
fi
done
if [[ "${STATUS}" == "Running" ]]; then
echo "ERROR: Timeout after ${TIMEOUT}s"
exit 1
fi
# ---------------------------------------------------------------------------
# Step 3 — Evaluate
# ---------------------------------------------------------------------------
if [[ "${STATUS}" != "Completed" ]]; then
echo "FAILED: Job ended with status '${STATUS}'"
exit 1
fi
echo "Job completed successfully."
exit 0
Example: Execute a Standard Test with waitUntilComplete (Python)
For individual standard tests, you can skip polling entirely by setting waitUntilComplete to true. The API call blocks until the test finishes and returns the result directly.
import requests
import os
import sys
VALIDATAR_API_URL = os.environ.get("VALIDATAR_API_URL")
VALIDATAR_API_TOKEN = os.environ.get("VALIDATAR_API_TOKEN")
PROJECT_ID = int(os.environ.get("VALIDATAR_PROJECT_ID", "0"))
TEST_ID = int(os.environ.get("VALIDATAR_TEST_ID", "0"))
HEADERS = {
"x-val-api-token": VALIDATAR_API_TOKEN,
"Content-Type": "application/json"
}
BASE = f"{VALIDATAR_API_URL}/core/api/v1"
# Execute synchronously — no polling needed
print(f"Executing standard test {TEST_ID} (synchronous)...")
execute_url = f"{BASE}/projects/{PROJECT_ID}/tests/{TEST_ID}/execute"
payload = {
"saveInRepository": True,
"waitUntilComplete": True
}
response = requests.post(execute_url, headers=HEADERS, json=payload)
response.raise_for_status()
execution = response.json()
batch_key = execution["executionKey"]
print(f"Execution complete. Batch key: {batch_key}")
# Get the summary to check the result
summary_url = f"{BASE}/projects/{PROJECT_ID}/tests/{TEST_ID}/results/{batch_key}"
summary_response = requests.get(summary_url, headers=HEADERS)
summary_response.raise_for_status()
summary = summary_response.json()
result = summary.get("result", "Unknown")
print(f"Test: {summary.get('name')}")
print(f"Result: {result}")
print(f"Started: {summary.get('dateStarted')}")
print(f"Completed: {summary.get('dateCompleted')}")
if result == "Passed":
print("Test passed. Pipeline may continue.")
sys.exit(0)
else:
print(f"Test did not pass (result: {result}).")
sys.exit(1)
Adapting for Your Orchestrator
The scripts above work anywhere you can run Python, PowerShell, or Bash. Here's how to call them from common orchestration platforms:
| Orchestrator | How to Run | Notes |
|---|---|---|
| Control-M | Web Services job type or OS job running a script | Use the Python or PowerShell script as the job command |
| Prefect | @task decorator calling requests in a flow |
Wrap the Python logic in a Prefect task; use Prefect Blocks for credentials |
| Dagster | @op decorator with requests in a job |
Wrap the Python logic in a Dagster op; use Resources for credentials |
| dbt Cloud | Webhooks triggering an external script | dbt Cloud can call a webhook on model completion; the webhook runs the Validatar script |
| Luigi | Task subclass with requests in run() |
Wrap the Python logic in a Luigi Task |
| SSIS | Execute Process task running PowerShell | Point the task at the PowerShell script; pass parameters via SSIS variables |
| Talend | tSystem component or tRESTClient | Use tSystem to call the script, or tRESTClient for direct API calls |
Troubleshooting
401 or 403 Response
- Verify the
x-val-api-tokenheader name is exact (notAuthorizationorBearer) - Confirm the token has the Execution scope
- Check that the token user has access to the project
Timeout Without Completion
- Increase
TIMEOUT_SECONDSif your jobs are expected to run longer than 30 minutes - Check the Validatar UI to see if the execution is still running or has an error
- Verify the job has tests assigned to it — an empty job may behave unexpectedly
Connection Refused or Timeout
- Verify
VALIDATAR_API_URLis correct (e.g.,https://mycompany.cloud.validatar.com) - Check network connectivity — if Validatar Server is behind a firewall, the orchestrator must be able to reach it
- For Cloud instances, verify no corporate proxy is blocking the connection
Empty Test Results in Job Summary
- The
testsarray in the job summary may not be populated until the job status isCompleted - Ensure you're reading the final poll response, not an intermediate one