Any platform over HTTP¶
There is no SDK requirement. If your tool can make an HTTP POST, it can report runs. The full field reference is in Recording runs; these are working starting points for the platforms we see most.
In every example: report failures too (wire the error path), and pass the
job id your platform already has as external_id so retries dedupe.
curl / bash¶
curl -sS -X POST "$LUMATRACK_URL/api/v1/runs" \
-H "Authorization: Bearer $LUMATRACK_KEY" \
-H "Content-Type: application/json" \
-d '{"automation": "cert-renewal", "status": "success", "source": "cron", "external_id": "'"$(date +%Y%m%d)"'-cert-renewal"}'
Ansible¶
A task at the end of the play; add a rescue block that posts
status: failure.
- name: Report run to LumaTrack
ansible.builtin.uri:
url: "{{ lumatrack_url }}/api/v1/runs"
method: POST
headers:
Authorization: "Bearer {{ lumatrack_key }}"
body_format: json
body:
automation: os-patching
status: success
source: ansible
units: "{{ ansible_play_hosts_all | length }}"
external_id: "{{ awx_job_id | default(omit) }}"
status_code: [200, 201, 202]
GitHub Actions¶
The published action is one step, reports failures and cancellations honestly, and never breaks your pipeline when LumaTrack is unreachable:
- name: Report run to LumaTrack
if: always()
uses: LumaTrack/report-run@v1
with:
api-key: ${{ secrets.LUMATRACK_KEY }}
automation: deploy-pipeline
status: ${{ job.status }}
The action reports to https://lumatrack.io unless you pass base-url, which
is only needed on a self-hosted or custom domain.
The action also takes units (per-unit valuation), duration-seconds,
failure-reason, and a metadata JSON object; retries are idempotent
via the default external id. Prefer plain curl? The equivalent request:
- name: Report run to LumaTrack
if: always()
env:
LUMATRACK_URL: ${{ vars.LUMATRACK_URL }}
LUMATRACK_KEY: ${{ secrets.LUMATRACK_KEY }}
run: |
STATUS="${{ job.status == 'success' && 'success' || 'failure' }}"
curl -sS -X POST "$LUMATRACK_URL/api/v1/runs" \
-H "Authorization: Bearer $LUMATRACK_KEY" \
-H "Content-Type: application/json" \
-d "{\"automation\": \"deploy-pipeline\", \"status\": \"$STATUS\", \"source\": \"github-actions\", \"external_id\": \"${{ github.run_id }}-${{ github.run_attempt }}\"}"
PowerShell¶
Full recipe with retry-safe function and RMM notes: PowerShell & RMM.
$Body = @{
automation = "ad-user-offboarding"
status = "success"
source = "powershell"
external_id = $JobId
} | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/v1/runs" `
-Headers @{ Authorization = "Bearer $ApiKey" } `
-ContentType "application/json" -Body $Body
Go¶
payload, _ := json.Marshal(map[string]any{
"automation": "log-rotation",
"status": "success",
"source": "go",
"external_id": jobID,
})
req, _ := http.NewRequest("POST", baseURL+"/api/v1/runs", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
C¶
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
var payload = JsonSerializer.Serialize(new {
automation = "mailbox-provisioning",
status = "success",
source = "csharp",
external_id = jobId,
});
var response = await http.PostAsync($"{baseUrl}/api/v1/runs",
new StringContent(payload, Encoding.UTF8, "application/json"));
Java¶
String payload = """
{"automation": "vm-snapshot-cleanup", "status": "success",
"source": "java", "external_id": "%s"}""".formatted(jobId);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/api/v1/runs"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
ServiceNow, Jira, and other ITSM platforms¶
Any platform with an outbound REST step works today: in ServiceNow, a Flow Designer REST step (or an outbound REST Message fired from a Business Rule) posting the JSON above; equivalents exist in Jira Automation and Zendesk webhooks. Purpose-built ITSM connectors with deflection measurement are on the LumaTrack roadmap; until then, outbound REST is the supported path.
MSP automation platforms (Rewst, Pia, custom RMM scripts)¶
Dedicated walkthroughs: Rewst, HaloPSA, PowerShell & RMM. For SOC platforms, see Tines.
MSP platforms that can make an outbound HTTP call at the end of a workflow report runs the same way. The pattern for a multi-client book:
- One LumaTrack client workspace per managed client (MSP plan). Each client org has its own API key, so the value ledger, the QBR report, and the audit trail stay per client by construction.
- Add one HTTP step at the end of each workflow (in Rewst: an HTTP
request action as the workflow's last step; consult your platform's
docs for the exact action name). POST the JSON below with the client
org's key. Map your platform's execution id to
external_idso retried workflows dedupe instead of double-counting. - Wire the failure path too. A workflow that only reports success produces a number nobody should put in front of a client.
{
"automation": "user-onboarding",
"status": "success",
"source": "rewst",
"external_id": "<your platform's execution id>",
"duration_seconds": 42,
"units": 3
}
Time-saved dashboards inside the platform remain useful as internal meters. What this step adds is the client-facing layer: dollars, per client, across every tool you run, with the methodology printed on the page. Setup cost, honestly: one HTTP step per workflow, then a few minutes of baseline entry per automation (the counterfactual minutes and rate the dollar figure is computed from; labeled as your assumption on every report).
If editing every workflow is impractical, two alternatives: a single "reporter" workflow your other workflows call as a sub-step, or a nightly backfill of an execution-log CSV export.