Dashboard API

Read routes on the Trakr dashboard app. Export runs, workflow stats, alert history, and overview metrics from scripts, CI, or Grafana.

For SDK ingest (write path), see the Ingest API.

Base URL

https://app.trakr.run

Use your dashboard origin in local development (for example http://localhost:3000).

Authentication

Read access tokens (recommended)

Create a read access token in the dashboard under Settings → API Keys (Access tokens table). Admins create tokens; the full secret is shown once at creation.

export TRAKR_READ_TOKEN="tk_read_..."

Pass the token in the Authorization header on every request:

Authorization: Bearer tk_read_[32 hex chars]
  • Tokens are org-scoped and read-only — separate from SDK ingest keys (tk_live_…).
  • Valid only on the allowlisted GET routes below.
  • Rate limit: 300 requests/minute per token; returns 429 with Retry-After.
  • tk_live_ ingest keys are rejected on read routes; tk_read_ tokens are rejected on ingest.
  • Never commit tokens to git or paste them into URLs — header only.

Session cookie (browser fallback)

The dashboard UI uses your Supabase session cookie. While logged in, browser DevTools sends cookies automatically. For one-off terminal tests, copy the cookie from DevTools → Application → Cookies.

Session cookies expire. Use read access tokens for CI, cron jobs, and long-lived integrations.

Write routes

POST, PATCH, and DELETE routes (billing, team, alert rules, token management) require a dashboard session. Bearer tokens are not accepted on write routes.

Allowlisted routes

Read access tokens work only on these GET handlers. All other routes return 401 for bearer tokens.

| Route | Notes | |---|---| | GET /api/runs | List runs | | GET /api/runs/[runId] | Run detail | | GET /api/runs/compare | Pro/Scale only — Starter returns 403 | | GET /api/workflows | Workflow summaries | | GET /api/workflows/[name]/stats | Workflow stats | | GET /api/workflows/[name]/tools | Tool breakdown | | GET /api/alert-events | Alert feed | | GET /api/metrics/overview | Overview metrics |

GET /api/org/context is excluded in v1.

Rotation and revocation

  1. Create a new access token in Settings → API Keys with a descriptive name (e.g. "Grafana export v2").
  2. Update your integration to use the new token.
  3. Revoke the old token from the same page — sets revoked_at immediately; in-flight requests may complete but new requests return 401.
  4. Audit — the token list shows last_used_at and prefix only; full secrets are never stored or returned after creation.

Rotate tokens when a team member leaves, after a suspected leak, or on a regular schedule for production integrations.

Security notes

  • Store tokens in a secrets manager (CI variables, Vault, etc.) — not in repo files or chat.
  • Logs and UI show the token prefix only (tk_read_abcd…); never log the full secret.
  • Tokens grant read access to all org observability data on allowlisted routes — treat them with the same care as SDK ingest keys.
  • Admin-only create/revoke; members can use a token an admin provides but cannot mint new ones.

Error format

{
  error: string;
  code?: string;
  details?: unknown[];
}

| Status | Meaning | |---|---| | 401 | Missing, invalid, or revoked token; or missing session on session-only routes | | 403 | Authenticated but not authorized (e.g. compare on Starter plan) | | 404 | Resource not found or outside your organization | | 429 | Rate limit exceeded — retry after Retry-After seconds |


GET /api/runs

List agent runs for your organization.

Query parameters:

| Param | Type | Default | Description | |---|---|---|---| | workflow | string[] | all | Filter by workflow names (repeatable) | | status | string[] | all | Filter by status | | from | ISO datetime | 30 days ago | Inclusive start | | to | ISO datetime | now | Inclusive end | | cost_min | number | — | Minimum cost in USD | | cost_max | number | — | Maximum cost in USD | | sort | string | started_at_desc | started_at_desc, started_at_asc, cost_desc, cost_asc, duration_desc, duration_asc | | cursor | string | — | Pagination cursor from a previous response | | limit | number | 50 | Max 100 |

Response (200):

{
  runs: AgentRunSummary[];
  next_cursor: string | null;
  total_count: number;
}

type AgentRunSummary = {
  id: string;
  workflow_name: string;
  run_id_external: string | null;
  status: "running" | "success" | "error" | "loop_detected" | "timeout";
  cost_usd: string;
  total_tokens: number;
  duration_ms: number | null;
  llm_call_count: number;
  tool_use_count: number;
  started_at: string;
  ended_at: string | null;
};

GET /api/runs/[runId]

Full run detail with nested LLM calls, tool events, and direct child runs.

Response (200):

{
  run: AgentRunDetail;
  child_runs: AgentRunSummary[];
  child_run_count: number;
  combined_cost_usd: string;
  alert_events: AlertEventSummary[];
}

alert_events includes up to five most recent alert firings for the run (newest first). Returns [] when none.

Response (404): Run missing or outside your organization.


GET /api/workflows

Aggregate stats per workflow.

Query parameters:

| Param | Type | Default | Description | |---|---|---|---| | from | ISO datetime | 30 days ago | Inclusive start | | to | ISO datetime | now | Inclusive end | | sort | string | total_cost_desc | total_cost_desc, run_count_desc, error_rate_desc, avg_latency_desc |

Response (200):

{
  workflows: WorkflowSummary[];
}

type WorkflowSummary = {
  workflow_name: string;
  run_count: number;
  avg_cost_usd: string;
  p95_cost_usd: string;
  total_cost_usd: string;
  error_rate: number;       // 0.0–1.0
  avg_duration_ms: number;
  last_run_at: string;
};

GET /api/alert-events

List fired alert events for your organization. Export alert history for reporting, on-call digests, or internal dashboards.

Query parameters:

| Param | Type | Default | Description | |---|---|---|---| | rule_id | string | all | Filter by alert rule ID | | resolved | boolean | all | true = resolved only, false = unresolved only | | from | ISO datetime | 30 days ago | Inclusive start | | to | ISO datetime | now | Inclusive end | | cursor | string | — | Pagination cursor from a previous response | | limit | number | 50 | Max 100 |

Response (200):

{
  alert_events: AlertEvent[];
  next_cursor: string | null;
}

type AlertEvent = {
  id: string;
  alert_rule_id: string;
  alert_rule_name: string;
  run_id: string | null;
  workflow_name: string | null;
  triggered_value: number;
  threshold_value: number;
  notification_sent: boolean;
  resolved_at: string | null;
  created_at: string;
};

To mark an event resolved, use PATCH /api/alert-events/[eventId] from the dashboard UI or with a session cookie — read tokens cannot write.


GET /api/runs/compare

Side-by-side comparison of two runs in the same workflow. Pro and Scale plans only.

Query: run_a, run_b (UUIDs)

Response (403): Starter plan.


Example

export TRAKR_APP_URL="https://app.trakr.run"
export TRAKR_READ_TOKEN="tk_read_..."

curl -sS "$TRAKR_APP_URL/api/runs?limit=10&sort=started_at_desc" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer $TRAKR_READ_TOKEN"

Grafana integration

Use the Infinity datasource plugin to pull Trakr workflow metrics into Grafana panels. Read access tokens are required — dashboard session cookies expire and are not suitable for Grafana.

1. Create a read token

In the Trakr dashboard: Settings → API Keys → Access tokens → create a token. Store the full tk_read_… secret in Grafana or your secrets manager.

2. Install Infinity

In Grafana: Connections → Add new connection → search Infinity → install the plugin.

3. Add a datasource

| Setting | Value | |---|---| | Type | JSON / URL | | URL | https://app.trakr.run/api/workflows?from={ISO}&to={ISO} | | Authentication | Bearer Token | | Bearer token | Your tk_read_… token |

Use a 24h window for a "Workflow cost (24h)" panel, for example:

  • from: 24 hours ago (ISO 8601)
  • to: now (ISO 8601)

4. Map fields (table panel)

| Infinity setting | Value | |---|---| | Root selector | workflows | | Columns | workflow_name, total_cost_usd, run_count, error_rate |

Create a Table visualization. error_rate is 0.0–1.0 (multiply by 100 in Grafana field overrides if you prefer percentages).

5. Optional — recent runs panel

Second datasource or query:

  • URL: https://app.trakr.run/api/runs?limit=10&sort=started_at_desc
  • Root selector: runs
  • Columns: workflow_name, status, cost_usd, duration_ms, started_at

Troubleshooting

| Symptom | Fix | |---|---| | 401 Unauthorized | Token missing, wrong prefix, or revoked — create a new read token | | Empty table | Check from/to cover a period with runs; widen the window | | 403 on compare route | Expected on Starter — use /api/workflows or /api/runs instead |

Copy-paste snippets are also in the dashboard under Settings → API Keys → REST API quickstart → Grafana (Infinity plugin).


CI scheduled export

Schedule a daily pull of workflow cost and error stats from your own CI or cron infrastructure. Trakr does not run scheduled jobs — your pipeline calls GET /api/workflows with a read access token.

1. Create a read token

In the Trakr dashboard: Settings → API Keys → Access tokens → create a token. Store the full tk_read_… secret in your CI secrets manager.

2. Add GitHub Actions secrets

In your GitHub repo: Settings → Secrets and variables → Actions → add:

| Secret | Value | |---|---| | TRAKR_READ_TOKEN | Your tk_read_… token | | TRAKR_APP_URL | https://app.trakr.run (or your dashboard origin) |

3. Add the workflow

Create .github/workflows/trakr-export.yml:

name: Trakr workflow export

on:
  schedule:
    - cron: '0 6 * * *'  # daily 06:00 UTC
  workflow_dispatch:

jobs:
  export:
    runs-on: ubuntu-latest
    steps:
      - name: Pull workflow stats (24h)
        env:
          TRAKR_APP_URL: ${{ secrets.TRAKR_APP_URL }}
          TRAKR_READ_TOKEN: ${{ secrets.TRAKR_READ_TOKEN }}
        run: |
          TO="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
          FROM="$(date -u -d '24 hours ago' +"%Y-%m-%dT%H:%M:%SZ")"
          curl -sS -f "$TRAKR_APP_URL/api/workflows?from=${FROM}&to=${TO}" \
            -H "Accept: application/json" \
            -H "Authorization: Bearer $TRAKR_READ_TOKEN"

Run manually via Actions → Trakr workflow export → Run workflow to verify a 200 response with a workflows array.

4. Generic cron alternative

On a Linux host with curl and GNU date, add to crontab (crontab -e):

# Daily 06:00 UTC — set TRAKR_APP_URL and TRAKR_READ_TOKEN in ~/.profile
0 6 * * * TO=$(date -u +"%Y-%m-%dT%H:%M:%SZ"); FROM=$(date -u -d '24 hours ago' +"%Y-%m-%dT%H:%M:%SZ"); curl -sS "$TRAKR_APP_URL/api/workflows?from=$FROM&to=$TO" -H "Accept: application/json" -H "Authorization: Bearer $TRAKR_READ_TOKEN"

Security

  • Rotate tokens via Settings → API Keys if a secret is leaked — revoke the old token after updating CI variables.
  • Never commit tokens to git or embed them in workflow files.

Troubleshooting

| Symptom | Fix | |---|---| | 401 Unauthorized | Token missing, wrong prefix, or revoked — create a new read token and update secrets | | Empty workflows array | Widen the from/to window or confirm runs exist in that period | | curl: command not found | Install curl on the runner or host |

Copy-paste snippets are also in the dashboard under Settings → API Keys → REST API quickstart → CI / scheduled export.

Post to Slack

Optionally extend your CI job to post a daily summary to Slack after pulling Trakr workflow stats. Trakr does not receive or store Slack webhook URLs — your pipeline POSTs directly to Slack.

1. Create a Slack incoming webhook

In Slack: Apps → Incoming Webhooks (or create a Slack app with an incoming webhook) → choose a channel (for example #agent-costs) → copy the webhook URL.

2. Add the GitHub Actions secret

In your GitHub repo: Settings → Secrets and variables → Actions → add:

| Secret | Value | |---|---| | SLACK_WEBHOOK_URL | Your https://hooks.slack.com/services/... URL |

Keep existing TRAKR_READ_TOKEN and TRAKR_APP_URL secrets from the scheduled export setup.

3. Extend the export job

Add a second step (or combine into one shell script) after the Trakr API pull. GitHub-hosted ubuntu-latest runners include jq pre-installed.

# Requires: TRAKR_APP_URL, TRAKR_READ_TOKEN, SLACK_WEBHOOK_URL
TO="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
FROM="$(date -u -d '24 hours ago' +"%Y-%m-%dT%H:%M:%SZ")"

RESPONSE="$(curl -sS -f "$TRAKR_APP_URL/api/workflows?from=${FROM}&to=${TO}" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer $TRAKR_READ_TOKEN")"

WORKFLOW_COUNT="$(echo "$RESPONSE" | jq '.workflows | length')"
TOTAL_COST="$(echo "$RESPONSE" | jq '[.workflows[].total_cost_usd | tonumber] | add // 0')"

SUMMARY="Trakr 24h: ${WORKFLOW_COUNT} workflows, \$${TOTAL_COST} total cost"

curl -sS -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d "{\"text\": \"${SUMMARY}\"}"

Example Slack message: Trakr 24h: 4 workflows, $12.34 total cost.

Security

  • Trakr never receives or stores SLACK_WEBHOOK_URL — only your CI runner uses it.
  • Rotate the Slack webhook and update the repo secret if the URL is leaked.
  • Revoke and recreate read tokens separately if TRAKR_READ_TOKEN is exposed.

Troubleshooting

| Symptom | Fix | |---|---| | jq: command not found | Install jq on self-hosted runners; GitHub-hosted Ubuntu includes it | | Slack invalid_payload | Ensure JSON is valid — escape quotes in the message body | | Empty summary (0 workflows) | Widen the from/to window or confirm runs exist in that period |

Copy-paste snippet is also in the dashboard under Settings → API Keys → REST API quickstart → CI / scheduled exportPost summary to Slack.