/api/v1 on the Build Results UI’s host. It serves
the data the UI displays: invocations and their configurations, metadata, metrics and logs, per-build
targets and target summaries, cross-invocation target statistics, and action history. Use it to feed
your own tooling, such as a release dashboard, a CI gate, or an internal report, or hand it to AI agents
through the built-in MCP server.
Where it’s available
The API is available on Aspect Cloud, athttps://app.aspect.build/api/v1, and on
Aspect Enterprise deployments running Aspect Workflows 6.0.30 or
later. On Aspect Enterprise it’s off by default. On a deployment
hosted by Aspect,
ask for it. On a self-hosted deployment,
your operator enables it (see the
).
Until it’s on, API requests are redirected to the browser login instead of answered.
The API is experimental. Routes, parameters and response shapes can change between Aspect Workflows
releases without a new version prefix; each such change is called out in that release’s notes. The
v1 in the path names the current contract, not a compatibility promise. Expect to revisit a client
when the deployment it talks to upgrades, and keep anything that can’t tolerate that off the API for
now.Prerequisites
An Aspect Cloud account, or an Aspect Enterprise deployment running Aspect Workflows 6.0.30 or later with the API enabled (see Where it’s available).If the deployment uses your own identity provider
- Register one identity provider application covering both the remote cluster and the Build Results UI. That’s what lets a token minted during CLI login be accepted by the API with no extra configuration.
- Register the Aspect CLI redirect URI on it. The redirect URI table lists it. If CLI logins to the remote cache or BES already work, it’s registered.
Set up authentication
Authentication uses the same CLI login as the remote cache. Nothing new is provisioned for the API.$TOKEN
above), use the CLI’s credential helper:
ASPECT_API_TOKEN_<NAME> (the deployment name uppercased, with every non-alphanumeric character
replaced by _). The session goes in the OS keyring where one is reachable (the kernel keyring on
Linux), and otherwise in a 0600 file at ~/.aspect/credentials.json:
How authentication works
Every/api/v1 request needs Authorization: Bearer <token> from the deployment’s configured
identity provider. The gateway verifies the token’s signature against the issuer’s published keys,
checks the audience, and resolves the token’s tenant to a provisioned organization. Any failure is a
401 that doesn’t say which check failed.
Clients that need to discover the authorization server programmatically read the RFC 9728
protected-resource metadata at GET /.well-known/oauth-protected-resource/api/v1 on the API host
(unauthenticated), then follow its authorization_servers.
Don’t build a 401-then-discover flow. With the authenticating proxy in front of the Build Results UI, an
unauthenticated
/api/v1 request is redirected to the identity provider rather than
answered with a challenge. Read the well-known document directly instead.Addressing a build
A build is addressed by its Aspect invocation ID, theid field in API responses, not by the
invocation ID Bazel printed, which is client-chosen and unique only per user. To go from a Bazel
invocation ID to the build’s resources, resolve it first:
links object with named relations, so after the first request a client
navigates by following links rather than assembling URLs.
Reading a build’s log
GET /invocations/<id>/log?page=N returns the build log in pages, zero-indexed. Every page reports
page and page_count, so start at ?page=0 and page forward. A page past the end is empty, since
the log grows while the build runs.
GET /invocations/<id>/log/tail is the one-request shortcut to the last page, useful for “why did
this build fail” tooling.
Cross-invocation target statistics
GET /target-stats?range=d7 lists the organization’s targets with their statistics over the lookback
window (d1, d3, d7, m1, m3 or y1). Adding label=<percent-encoded-label> narrows the same
response shape to one target. Supply repo=<repository> with the label to select that repository;
omitting it selects builds with no recorded repository. Other filters, ordering, or paging parameters
are rejected in this form (they return a 400), and the collection-wide profiled_invocations_daily series is empty. A label
with no builds in the window returns an empty page, not a 404.
GET /target-invocations?label=…&range=… lists the builds that built one target. Bazel labels are
always query parameters, never path segments, because a label contains / and :.
Action performance history
GET /api/v1/action-history reads execution-log records for an exact action-owner label, including
private or transitive labels without a target completion record. Use this endpoint to compare a
build action before and after a performance change.
Action history requires Aspect Workflows 6.0.33 or later. An older deployment returns 404.
label, start, and end are required. Times are RFC 3339 timestamps and filter the invocation’s
received time, with an inclusive start and exclusive end. A request may span at most 31 days; query
separate windows for longer comparisons. Repository and branch filters are exact matches. Omitting
them includes all repositories and branches within your authenticated organization.
Cache filtering selects whole invocation/label records:
cache=hit: all recorded spawns were cached, or the label was locally cached.cache=miss: at least one spawn was not cached. Mixed records retain their cached-spawn counts.- Omit
cacheto include both outcomes.
entries: one record per invocation and label, newest first, with its Aspect invocationid, repository, branch, commit, spawn/cache counts, execution-wall-time sum, and longest-path timings.total: matching records before pagination. Followlinks.nextwith the same time window;limitdefaults to 20 and accepts 1–100, andoffsetdefaults to zero.summary: counts and timing aggregates for the entire filtered window, independent of pagination.execution_countis recorded spawns minus cache hits.exec_wall_ms_totalsums recorded execution wall times; it isn’t elapsed build time because actions may run concurrently.daily: the same aggregates per UTC date whendaily=true. Days without records are omitted.
exec_wall_ms_p50, exec_wall_ms_p90, and
exec_wall_ms_p99 use exact interpolated percentiles of those stored totals. Cached records are
included unless filtered out, so use cache=miss when comparing execution performance. A mixed
record’s timing is still its full stored sum; this endpoint can’t split it into individual spawns.
Empty selections return zero counts, null percentiles, and empty arrays. History depends on retained,
ingested execution logs: an empty result doesn’t prove the action never ran. Ingestion can add or
update records while you paginate. Results are cached; repeating the same query within 30 seconds
may return the previous result. After ingestion completes, allow the cache to refresh before
re-fetching for a stable comparison.
When the service is busy, a query may wait up to five seconds before returning
503 service_unavailable. Wait for the Retry-After interval before retrying.
Conventions
- Every route is a
GET. - Pagination is
limit(1–100) andoffset. Every list response carries the unpaginatedtotal. - An unknown query parameter is a
400naming the valid fields, never silently ignored. - Errors are
{"code": …, "message": …}. On 6.0.33,codeis one ofbad_request(400),unauthorized(401),not_found(404),internal(500), orservice_unavailable(503). A build belonging to another organization is a404, never a403. - Byte counts and recorded durations are integers; interpolated percentiles can be fractional;
linksrelation names are snake_case. - Metadata filters repeat as
metadata=key:value. Values for the same key are ORed, distinct keys ANDed.
API reference
The deployment serves its own reference documentation:- Browsable reference at
https://app.<your-domain>/api/v1/docs. Open it in a signed-in browser session. - OpenAPI document at
https://app.<your-domain>/api/v1/openapi.json. Fetch it with a bearer token, for client generation or import into API tooling. Itsinfo.versiontracks the API contract (1.0.0under/api/v1), not the deployment’s Workflows version.
See also
- Connect an AI assistant to build results with MCP: the Aspect CLI’s MCP server over this API, with per-client setup, the published tools, and troubleshooting.
- Build Results UI: the web interface serving the same data.

