The Run History API tells you how your reports ran. This endpoint tells you what your reports are: one record per report with its uid, name, type, schedule, delivery destinations, output formats, and the databases it queries — plus a link to the report's full YAML configuration. Use it to keep an external inventory (a CMDB, HubSpot, a monitoring project, your warehouse) in sync without exporting YAML files by hand.
Authentication is the same one-token flow as the other APIs: create a Personal Access Token under Settings → Access Tokens (/a/tokens), then exchange it for a short-lived access key. The Digest API guide walks through both steps; the short version:
JWT=$(curl -s -X POST https://pushmetrics.io/api/v1/security/exchange \
-H "Authorization: Bearer pmpat_YOUR_TOKEN" | jq -r .access_token)
The inventory endpoint
curl -s "https://pushmetrics.io/api/v1/report/inventory?page_size=100" \
-H "Authorization: Bearer $JWT"
All parameters are optional:
| Parameter | Meaning |
|---|---|
type |
Only reports of one type: default (report), notebook, tableau_embed, or agent_run |
active |
true for reports with an active schedule, false for the rest |
name |
Case-insensitive name contains |
page |
Page number, starting at 0 |
page_size |
Rows per page, 1 to 500. Default 100. |
Invalid input returns a 422 with a message saying what's wrong.
What comes back
{
"count": 143,
"page": 0,
"page_size": 100,
"result": [
{
"uid": "pjoVBM6oYP",
"name": "Weekly KPI Report",
"type": "default",
"active": true,
"schedule": {
"active": true,
"rrule": "DTSTART:20260101T090000\nRRULE:FREQ=WEEKLY;BYDAY=MO",
"next_run": "2026-08-17T09:00:00Z",
"last_run": "2026-08-10T09:00:00Z"
},
"webhook_active": false,
"destinations": ["email", "slack"],
"output_formats": ["pdf", "xlsx"],
"databases": [
{"uid": "aK3mZpQ2vX", "name": "Snowflake Prod"}
],
"folder": ["Clients", "Acme"],
"tags": ["kpi", "weekly"],
"created_by": "jane@acme.com",
"created_at": "2025-11-03T14:22:10Z",
"updated_at": "2026-08-01T08:15:44Z",
"config_url": "/api/v1/report/pjoVBM6oYP/config"
}
]
}
| Field | Meaning |
|---|---|
uid |
The report's stable identifier — the same one in the report's URL in the app. Use it as your sync key. |
type |
default (report), notebook, tableau_embed, or agent_run |
active |
Whether the report's schedule is switched on. false also for reports that were never scheduled — check schedule to tell the two apart. |
schedule |
The schedule as an iCalendar RRULE, with the next and last scheduled run (UTC). null when the report has never had a schedule. |
webhook_active |
Whether the report can be triggered by its webhook URL |
destinations |
Where the report delivers: email, slack, sftp, webhook, aws_s3, gcp_bucket, azure_storage_blob, gdrive |
output_formats |
File formats the report produces: csv, xlsx, pdf, png, pptx, html_table |
databases |
The database connections the report's SQL queries use. name is null if the connection was deleted. |
folder |
Folder path in the app, root first |
created_by |
Email of the report's creator |
config_url |
Path to the report's full YAML configuration (below) |
Rows are ordered newest first. count is the total matching your filters, so count > (page + 1) * page_size means there are more pages.
You see the reports shared with you; workspace admins see every report in the workspace. The token's workspace binding applies, same as everywhere else.
Fetching a report's full configuration
Each row's config_url points at the report's complete configuration — the same YAML the in-app export produces, covering every block with its SQL, delivery settings, recipients, schedule, and webhook:
curl -s "https://pushmetrics.io/api/v1/report/pjoVBM6oYP/config" \
-H "Authorization: Bearer $JWT"
The response is text/plain YAML, not JSON. It's the source-of-truth format PushMetrics itself uses for git sync and publishing, so anything configured on the report is in there.
Useful one-liners
BASE="https://pushmetrics.io/api/v1/report"
# The whole inventory as a CSV: uid, name, active, destinations
curl -s "$BASE/inventory?page_size=500" -H "Authorization: Bearer $JWT" \
| jq -r '.result[] | [.uid, .name, .active, (.destinations | join("+"))] | @csv'
# Every actively scheduled report with its next run
curl -s "$BASE/inventory?active=true&page_size=500" -H "Authorization: Bearer $JWT" \
| jq -r '.result[] | [.schedule.next_run, .name] | @tsv' | sort
# Dump every report's YAML into files named by uid
for uid in $(curl -s "$BASE/inventory?page_size=500" -H "Authorization: Bearer $JWT" \
| jq -r '.result[].uid'); do
curl -s "$BASE/$uid/config" -H "Authorization: Bearer $JWT" > "$uid.yaml"
done
A small Python client
import requests
BASE = "https://pushmetrics.io/api/v1"
PAT = "pmpat_..." # from your secrets store
def get_jwt():
r = requests.post(f"{BASE}/security/exchange",
headers={"Authorization": f"Bearer {PAT}"})
r.raise_for_status()
return r.json()["access_token"]
def fetch_reports(jwt, **params):
"""Yield every report matching the filters, walking the pages."""
page = 0
while True:
r = requests.get(f"{BASE}/report/inventory",
params={**params, "page": page, "page_size": 500},
headers={"Authorization": f"Bearer {jwt}"})
if r.status_code == 401: # key expired mid-walk, get a fresh one
jwt = get_jwt()
continue
r.raise_for_status()
body = r.json()
yield from body["result"]
page += 1
if page * body["page_size"] >= body["count"]:
return
def fetch_yaml(jwt, uid):
r = requests.get(f"{BASE}/report/{uid}/config",
headers={"Authorization": f"Bearer {jwt}"})
r.raise_for_status()
return r.text
jwt = get_jwt()
for report in fetch_reports(jwt):
print(f"{report['uid']} {report['name']} → {report['destinations']}")
# config = fetch_yaml(jwt, report["uid"]) # when you need the full detail
Good practices
- Key your sync on
uid. It never changes, survives renames and moves, and matches the report's URL in the app and thereport_uidin the Run History API. - Use
updated_atto skip unchanged reports — only fetch the YAML for rows whoseupdated_atmoved since your last sync. - A daily sync is plenty. Report configurations change at human speed; the Run History API is the endpoint to poll more often.
- Revoke tokens you stop using on the Access Tokens page.
Related
- Run History API — one record per execution of these reports, with status, duration, and errors.
- Digest API — run-health rollups over a time window.