CI

List run history for a check (CI/CD runs and agent/heartbeat runs)

Returns the last N runs for the check, newest first — both CI/CD runs (pings that carry structured ci_meta, received from a CI/CD provider webhook) and agent/heartbeat runs (pings that carry only a rid set at /start, with no ci_meta). A ping with neither ci_meta nor a rid is not a run and is excluded.

CI runs include the full failure context decoded from ci_meta: run_url, commit_sha, branch, actor, failing_stage, duration_s, and outcome. These fields are CI-only — they are simply absent (omitted, not null or empty string) on an agent/heartbeat run. When a matching incident (opened within ±10 minutes of the ping) exists, incident_cause, incident_detail, and incident_resolved are populated on either kind — enabling unattended failure triage without following links to the CI provider.

duration_ms is separate from duration_s and is NOT CI-only: it is the wall-clock duration LastPing itself measured from the run's /start -> success timing, present on any run (CI or agent/heartbeat) whose success ping paired with its start. Use it to answer "how long does this job normally take?" for a non-CI monitor, where duration_s is never populated.

Every entry also carries the run id (rid) and, when the run reported progress markers to /<uuid>/step?rid=…, the steps it reached. A run that stalled therefore names the step it wedged on without a second call. Steps are matched on rid, so they appear only when the job or agent posts /step with the same run id it started with.

Always returns a JSON array (never null).

get/api/v1/checks/{id}/runs

Request

  • Base URL: https://app.lastping.dev
  • URL: https://app.lastping.dev/api/v1/checks/{id}/runs
  • Auth: API key in header X-Api-Key

Query parameters

limitinteger
Example:20

Maximum number of runs to return (default 20, max 100).

Response

Array of runs — CI runs and agent/heartbeat runs (may be empty).

idstring uuid required

Ping UUID that represents this CI run.

kindstring required

Ping kind. One of success, start, fail, log, cancel, blocked, note (see the Ping schema); CI/CD webhooks typically post success or fail.

received_atstring date-time required

RFC 3339 UTC timestamp when the ping was received.

ridstring

Run id this ping carried (?rid=), omitted when the ping carried none. It is the key steps are matched on.

titlestring

Title for this run, stored on the run's /start ping — distinct from body_excerpt. Matched on rid the same way steps is — both pings of a run (its start and its terminal ping) carry it. Set by whichever call reaches it FIRST with a non-empty title: the body of the run's own /start call, or a later POST .../title?rid=<run-id> sent any time while the run is still open — same request shape as /blocked and /note, but (unlike them) it records no ping of its own: it only ever sets title on the run's existing /start ping, so it never appears as a kind in the Ping schema. Only the first non-empty write counts; neither a later /start body nor a later /title call can change a title once one is set. Omitted when nothing has set a title yet, which is the common case: every existing monitor's runs are untitled until a caller starts setting one.

run_urlstring

CI-only. Direct URL to the CI/CD run page. Omitted when unavailable, and always omitted on an agent/heartbeat run.

commit_shastring

CI-only. Full or abbreviated commit SHA that triggered the run. Omitted when unavailable, and always omitted on an agent/heartbeat run.

branchstring

CI-only. Branch name that triggered the run. Omitted when unavailable, and always omitted on an agent/heartbeat run.

actorstring

CI-only. Username or identity that triggered the run. Omitted when unavailable, and always omitted on an agent/heartbeat run.

failing_stagestring

CI-only. Name of the failing step or job (omitted when unavailable, and always omitted on an agent/heartbeat run).

Availability differs by provider:

  • GitLab CI — always populated on a failed pipeline, from the stage of the first failed entry in the hook's builds[].
  • GitHub Actions — requires the repository webhook to subscribe to Workflow jobs (workflow_job) in addition to Workflow runs. Only workflow_job carries per-step conclusions; with workflow_run alone this field is always omitted.
  • Jenkins — never populated. The Notification Plugin payload reports only the build's overall result and carries no per-stage or per-step detail.
duration_sinteger

CI-only. Run duration in seconds. Omitted when unavailable or zero, and always omitted on an agent/heartbeat run.

duration_msinteger

Wall-clock duration in milliseconds, measured by LastPing from the run's /start -> success timing (pings.duration_ms). Present on ANY completed run — CI or agent/heartbeat — whose success ping paired with a preceding start on the same rid; omitted otherwise.

Distinct from duration_s: that field is CI-only and self-reported by the provider from ci_meta, this one is computed by LastPing for every run kind. The two can each be present without the other and must not be treated as confirming each other.

outcomestring

CI-only. Normalised run outcome string from the CI provider (e.g. failure, success). Always omitted on an agent/heartbeat run.

incident_causestring

Cause from the correlated incident (e.g. silence, fail, overrun, never_started, runaway, stalled, blocked, upstream) if one was opened within ±10 minutes of this run. Empty when no incident correlates.

incident_detailstring

Log excerpt attached to the correlated incident via the /ci/{id}/detail endpoint. Empty when no detail has been posted or no incident correlates.

incident_resolvedboolean required

True when the correlated incident has been closed (resolved). False when the incident is still open or when no incident correlates.

span_countinteger nullable required

Number of OTLP spans recorded for this run. Null when the run was never traced.

tokens_ininteger nullable required

Sum of gen_ai.usage.input_tokens across this run's GenAI spans. Null when the run was never traced.

tokens_outinteger nullable required

Sum of gen_ai.usage.output_tokens across this run's GenAI spans. Null when the run was never traced.

cost_usdstring nullable required

Summed cost of this run's GenAI spans, as decimal text, never a JSON number. Each span's cost is the one its SDK reported (gen_ai.usage.cost) or, when it reported none, LastPing's estimate from the model's published price and the span's token counts (cost_source says which). Null when the run was never traced, or when no span has either: no reported cost and no known price for its model.

cost_sourcestring required

What cost_usd is made of. A plain string, not an enum, so a new value never breaks a client: client when every priced call's cost was reported by the client (the exporter's own figure, or Claude Code's per-call cost), estimated when LastPing priced every call at API list prices, mixed when the sum holds both, empty when cost_usd is null.

Example response

[
  {
    "id": "a0b1c2d3-0000-0000-0000-000000000001",
    "kind": "fail",
    "received_at": "2026-07-20T10:00:00Z",
    "rid": "9876543210",
    "title": "nightly backup",
    "steps": [
      {
        "seq": 2,
        "name": "db migrate",
        "at": "2026-07-20T10:04:00Z"
      }
    ],
    "run_url": "https://github.com/acme/repo/actions/runs/9876543210",
    "commit_sha": "deadbeefcafe0000",
    "branch": "main",
    "actor": "octocat",
    "failing_stage": "go test ./...",
    "duration_s": 120,
    "duration_ms": 128734,
    "outcome": "failure",
    "incident_cause": "fail",
    "incident_detail": "STEP failed: go test ./... exited with code 1",
    "span_count": 14,
    "tokens_in": 1820,
    "tokens_out": 340,
    "cost_usd": "0.021400",
    "cost_source": "estimated"
  }
]

Changes

No recorded changes to this operation across all 2 revisions of this API.