Sippy has a simple REST API at /api. The API is used by the front-end.
The docs here may not be fully up-to-date, although we do try not to
break backwards compatability where possible.
For exact API usage, you can use your browser's web developer tools to examine the requests we make.
The Sippy Chat API has been removed, including /api/chat and its streaming,
persona, model, prompt, rating, and conversation endpoints. The chat capability
and --chat-api server flag are no longer available. The frontend /chat and
nested chat URLs display a transition page directing users to Chai Bot in Slack.
The API's that support filtering, as indicated in their docs below, use a filtering format as follows. The format is similar to the filtering options used by Material UI's data tables internally.
An individual filter is JSON, in the following format:
{
"columnName": "name",
"operatorValue": "contains",
"value": "aws"
}- String operators are: contains, starts with, ends with, equals, is empty, is not empty.
- Numerical operators are: =, !=, <, <=, >, >=
- Array operators are: contains
An optional 'not' field may be specified which inverts the operator. For example, the below filter means name does not contain aws:
{
"columnName": "name",
"not": true,
"operatorValue": "contains",
"value": "aws"
}A composed filter consists of one or more filters, along with a link operator. A link operator is either and or or.
Example:
{
"linkOperator": "and",
"items": [
{
"columnName": "name",
"operatorValue": "contains",
"value": "aws"
},
{
"columnName": "name",
"not": true,
"operatorValue": "contains",
"value": "upgrade"
}
]
}The filter should be URI encoded json in the filter parameter.
You may sort results by any sortable field in the item by specifying sortField, as well sort with the value
asc or desc.
Endpoint: /api/health
Returns a summary of overall release health, including the percentage of successful runs of each, as well as a summary of variant success rates.
Example response
{
"indicators": {
"infrastructure": {
"current": {
"percentage": 88.88888888888889,
"runs": 1998
},
"previous": {
"percentage": 95.31914893617022,
"runs": 1880
}
},
"install": {
"current": {
"percentage": 96.53083700440529,
"runs": 3632
},
"previous": {
"percentage": 98.8409703504043,
"runs": 3710
}
},
"upgrade": {
"current": {
"percentage": 98.50299401197606,
"runs": 334
},
"previous": {
"percentage": 99.52941176470588,
"runs": 425
}
}
},
"variants": {
"current": {
"success": 2,
"unstable": 1,
"failed": 17
},
"previous": {
"success": 3,
"unstable": 6,
"failed": 11
}
},
"last_updated": "2021-08-09T14:12:09.319089659Z"
}| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
* indicates a required value.
| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
* indicates a required value.
Example response
{
"column_names": [
"All",
"aws"
],
"description": "Install Rates by Operator by Variant",
"tests": {
"Overall": {
"All": {
"id": 0,
"name": "All",
"current_successes": 4045,
"current_failures": 166,
"current_flakes": 0,
"current_pass_percentage": 96.05794348135834,
"current_runs": 4211,
"previous_successes": 4260,
"previous_failures": 54,
"previous_flakes": 0,
"previous_pass_percentage": 98.74826147426981,
"previous_runs": 4314,
"net_improvement": 0,
"bugs": null,
"associated_bugs": null
},
"aws": {
"id": 0,
"name": "aws",
"current_successes": 361,
"current_failures": 6,
"current_flakes": 0,
"current_pass_percentage": 98.36512261580381,
"current_runs": 367,
"previous_successes": 371,
"previous_failures": 4,
"previous_flakes": 0,
"previous_pass_percentage": 98.93333333333332,
"previous_runs": 375,
"net_improvement": 0,
"bugs": null,
"associated_bugs": null
}
}
},
"title": "Install Rates by Operator"
}| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
* indicates a required value.
Endpoint: /api/jobs
Example response
[
{
"id": 51,
"name": "periodic-ci-openshift-release-master-ci-4.9-e2e-gcp-upgrade",
"brief_name": "e2e-gcp-upgrade",
"variants": [
"gcp",
"upgrade"
],
"current_pass_percentage": 10.030395136778116,
"current_projected_pass_percentage": 10.784313725490197,
"current_runs": 329,
"previous_pass_percentage": 35.78274760383386,
"previous_projected_pass_percentage": 37.45819397993311,
"previous_runs": 313,
"net_improvement": -25.752352467055744,
"test_grid_url": "https://testgrid.k8s.io/redhat-openshift-ocp-release-4.9-informing#periodic-ci-openshift-release-master-ci-4.9-e2e-gcp-upgrade",
"bugs": [],
"associated_bugs": [
{
"id": 1983758,
"status": "NEW",
"last_change_time": "2021-07-27T16:59:31Z",
"summary": "gcp upgrades are failing on \"Cluster frontend ingress remain available\"",
"target_release": [
"---"
],
"component": [
"Routing"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1983758"
}
]
}
]| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
| filter | Filter | Filters the results by the specified value. Can be specified multiple times, e.g. filterBy=hasBug&filterBy=name&job=aws | See filtering |
| sortField | Field name | Sort by this field | |
| sort | asc / desc | Sort type, ascending or descending | "asc" or "desc" |
| limit | Integer | The maximum amount of results to return | N/A |
* indicates a required value.
Endpoint: /api/jobs/details
A summary of runs for job(s). Results contains of the following values for each job:
- S success
- F failure (e2e )
- f failure (other tests)
- U upgrade failure
- I setup failure (installer)
- N setup failure (infra)
- n failure before setup (infra)
- R running
Example response
{
"jobs": [
{
"name": "periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6",
"results": [
{
"timestamp": "2021-08-06T03:43:59Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423429598720299008"
},
{
"timestamp": "2021-08-04T03:59:33Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1422754032564310016"
},
{
"timestamp": "2021-08-05T21:24:04Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423394362347229184"
},
{
"timestamp": "2021-08-09T05:03:12Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1424597097709047808"
},
{
"timestamp": "2021-08-07T14:25:08Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1424003666343366656"
},
{
"timestamp": "2021-08-07T09:15:13Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423925674229370880"
},
{
"timestamp": "2021-08-06T23:20:49Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423776089259380736"
},
{
"timestamp": "2021-08-06T19:56:10Z",
"result": "S",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423724523844276224"
},
{
"timestamp": "2021-08-07T18:34:51Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1424066513538650112"
},
{
"timestamp": "2021-08-05T19:08:52Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423360364472438784"
},
{
"timestamp": "2021-08-06T19:16:02Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1423714481237659648"
},
{
"timestamp": "2021-07-27T13:24:55Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1420007279679246336"
},
{
"timestamp": "2021-07-28T12:16:03Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1420352338517823488"
},
{
"timestamp": "2021-07-30T04:20:30Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1420957438630170624"
},
{
"timestamp": "2021-07-29T00:56:17Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1420528516700573696"
},
{
"timestamp": "2021-07-27T15:00:51Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1420031423921786880"
},
{
"timestamp": "2021-07-27T05:53:11Z",
"result": "F",
"url": "https://prow.ci.openshift.org/view/gcs/origin-ci-test/logs/periodic-ci-openshift-release-master-nightly-4.9-e2e-metal-ipi-ovn-ipv6/1419893597473345536"
}
]
}
],
"start": "2021-07-26",
"end": "2021-08-09"
}| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
| job | String | Return only jobs containing only containing this value in their name | N/A |
| limit | Integer | The maximum amount of results to return | N/A |
Endpoints:
GET /api/jobs/labelslists label definitions.POST /api/jobs/labelscreates a label definition.GET /api/jobs/labels/{id}retrieves one label definition.PUT /api/jobs/labels/{id}fully replaces one label definition.DELETE /api/jobs/labels/{id}soft-deletes one label definition.
Label definitions include the immutable id, human-readable label_title, Markdown
explanation, optional hide_display_contexts, and bugs. The bugs field is an array of Jira
issue keys such as OCPBUGS-12345. Responses always return an array for bugs, including [] for
labels without associated issues. Jira keys are validated syntactically, but the API does not look
up issues in Jira.
PUT requests use full-replacement semantics. Clients must send the complete label definition,
including bugs and hide_display_contexts when those values should be retained.
Endpoint: POST /api/jobs/runs/reevaluate
Re-runs all symptom definitions against the artifacts for specified job runs and updates
BigQuery, GCS, and PostgreSQL with the results. Requires --enable-write-endpoints.
{
"prow_job_build_ids": ["1234567890", "0987654321"],
"dry_run": false
}Maximum 10,000 unique job run IDs per request. IDs must be numeric strings.
The response contains batch_id, requested, and a links.status URL for polling.
{
"batch_id": "d15dff1f-431c-48db-aa37-628ab42d755e",
"links": {
"status": "http://localhost:8080/api/jobs/runs/reevaluate/d15dff1f-431c-48db-aa37-628ab42d755e"
},
"requested": 3
}Poll the status link with GET /api/jobs/runs/reevaluate/{batch_id} for batch
counts and per-item progress. Each item includes item_key, item state, and
an optional result object. Most state values come directly from River's job
state enum (e.g. available, running, completed, cancelled, discarded).
Two synthetic states cover items outside River's lifecycle: not_enqueued (the
batch fan-out has not yet created a River job for this item) and orphaned (the
item references a River job that no longer exists, e.g. cleaned up by River's
job retention):
{
"batch_id": "<id>",
"status": "running",
"requested": 4,
"enqueued": 3,
"deduped": 1,
"completed": 2,
"failed": 1,
"running": 1,
"pending": 0,
"items": [
{
"item_key": "1234567890",
"state": "completed",
"result": {
"prow_job_build_id": "1234567890",
"status": "success",
"symptoms_evaluated": 42,
"symptoms_matched": ["SomeSymptom"],
"labels_applied": ["SomeLabel"],
"bq_entries_written": 1,
"gcs_artifacts_written": 1,
"postgres_updated": true,
"links": {
"job_run": "https://prow.ci.openshift.org/view/gs/test-platform-results/logs/example/1234567890",
"symptom:SomeSymptom": "/api/jobs/symptoms/SomeSymptom"
}
}
},
...
]
}result contains the latest output recorded by the River job, including failed attempts
and dry-run matches. Retries replace output when they record a new result. Execution state
remains authoritative for queue progress; a failed attempt's result may be present while a
retry is pending. Deduplicated items read the same job output. Items without output, including
older jobs and jobs removed by River cleanup, omit result. Zero-valued optional result
fields are omitted. Results become available when the attempt finishes.
success- re-evaluation completed and all backends updated.missing_error- the job run ID was not found in the database.eval_error- artifact scanning failed (timeout, GCS error, database error).rewrite_error- scanning succeeded but writing to BQ/GCS/PostgreSQL failed.
Endpoint: DELETE /api/jobs/runs/reevaluate/{batch_id}
Requires --enable-write-endpoints. No request body is needed. Requests cancellation
of the batch's non-completed River jobs and marks the batch as cancelled. Jobs that
have already completed are left alone.
On success, returns 200 OK with the same batch status response shape as the status
endpoint above, including batch_id, status: "cancelled", counts, and items.
Running jobs may still be finishing when the response is returned; poll the status
endpoint for updated per-item progress.
If the batch is already complete, failed, or cancelled, returns 409 Conflict
(ErrBatchTerminal). For example, cancelling an already-cancelled batch returns:
{
"code": 409,
"message": "batch is already in a terminal status: batch d15dff1f-431c-48db-aa37-628ab42d755e has status \"cancelled\""
}Other errors: 400 Bad Request for an invalid batch UUID, 404 Not Found if the
batch does not exist, 503 Service Unavailable if batch cancellation is not
configured, and 500 Internal Server Error if cancellation fails unexpectedly.
Endpoint: /api/tests
| Option | Type | Description | Acceptable values |
|---|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 4.9) | N/A |
| filter | Filter | Filters the results by the specified value. | See filtering |
| sortField | Field name | Sort by this field | |
| sort | asc / desc | Sort type, ascending or descending | "asc" or "desc" |
| limit | Integer | The maximum amount of results to return | N/A |
filter supports a lifecycle field (equals or != operators only; other operators return a
400) to restrict results to a test lifecycle (blocking or informing). It narrows which
underlying test runs are aggregated; it is not returned as a field on results, and
blocking/informing runs for the same test are combined into a single row when no lifecycle filter
is applied. This filter is only supported against the Postgres-backed report (/api/tests); using
it against /api/tests/v2 (BigQuery) returns a 400, since the underlying BigQuery comparison
tables don't carry a lifecycle column.
Example response
[
{
"id": 253,
"name": "[sig-network-edge] Cluster frontend ingress remain available",
"current_successes": 554,
"current_failures": 31,
"current_flakes": 201,
"current_pass_percentage": 94.70085470085469,
"current_runs": 786,
"previous_successes": 734,
"previous_failures": 25,
"previous_flakes": 242,
"previous_pass_percentage": 96.70619235836627,
"previous_runs": 1001,
"net_improvement": -2.005337657511575,
"bugs": [
{
"id": 1980141,
"status": "POST",
"last_change_time": "2021-08-03T14:02:12Z",
"summary": "NetworkPolicy e2e tests are flaky in 4.9, especially in stress",
"target_release": [
"4.9.0"
],
"component": [
"Networking"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1980141"
},
{
"id": 1983829,
"status": "NEW",
"last_change_time": "0001-01-01T00:00:00Z",
"summary": "ovn-kubernetes upgrade jobs are failing disruptive tests",
"target_release": [
"4.9.0"
],
"component": [
"Networking"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1983829"
},
{
"id": 1981872,
"status": "NEW",
"last_change_time": "2021-08-03T17:13:35Z",
"summary": "SDN networking failures during GCP upgrades",
"target_release": [
"4.9.0"
],
"component": [
"Networking"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1981872"
}
],
"associated_bugs": [
{
"id": 1983758,
"status": "NEW",
"last_change_time": "2021-07-27T16:59:31Z",
"summary": "gcp upgrades are failing on \"Cluster frontend ingress remain available\"",
"target_release": [
"---"
],
"component": [
"Routing"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1983758"
},
{
"id": 1943334,
"status": "POST",
"last_change_time": "2021-07-23T10:58:19Z",
"summary": "[ovnkube] node pod should taint NoSchedule on termination; clear on startup",
"target_release": [
"---"
],
"component": [
"Networking"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1943334"
},
{
"id": 1987046,
"status": "POST",
"last_change_time": "2021-07-30T07:02:22Z",
"summary": "periodic ci-4.8-upgrade-from-stable-4.7-e2e-*-ovn-upgrade are permafailing on service/ingress disruption",
"target_release": [
"4.8.z"
],
"component": [
"Networking"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1987046"
}
]
}
]Endpoint: /api/feature_gates
Returns all feature gates and their test counts for a release. Each gate includes
lightweight HATEOAS links (ui_detail and api_detail) for navigation.
| Option | Type | Description |
|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 5.0) |
| filter | Filter | Filters the results. See filtering above. |
Endpoint: /api/feature_gates/{feature_gate}
Returns a single feature gate with full HATEOAS links for test queries
(gate_tests, install_tests, gate_job_tests, ui_detail).
The install_tests link is only present for gates whose name contains "Install".
The response includes a promotion object with promotion readiness data:
per-variant test pass rates, overall sufficiency, warnings, and errors.
The promotion evaluation is computed from the same data that the gate_tests
and install_tests HATEOAS links point to. Both the links and the promotion
logic use canonical filter definitions from
pkg/api/featuregatepromotion/filters.go, ensuring they always stay in sync.
| Option | Type | Description |
|---|---|---|
| release* | String | The OpenShift release to return results from (e.g., 5.0) |
| feature_gate | Path | The feature gate name (in the URL path) |
Endpoint: GET /api/component_readiness/triages
Lists triage records. Supports an optional view query parameter to filter triages
to those associated with regressions active in the specified component readiness view.
When view is omitted, all triages are returned (original behavior).
| Option | Type | Description | Acceptable values |
|---|---|---|---|
| view | String | Filter triages to those linked to regressions active in this view (e.g., 4.18-main). Optional; omit to return all triages. | N/A |
Endpoint: GET /api/component_readiness/triages/{id}
Returns a single triage record by ID.
Endpoint: POST /api/component_readiness/triages
Creates a new triage record.
Endpoint: PUT /api/component_readiness/triages/{id}
Updates an existing triage record.
Endpoint: DELETE /api/component_readiness/triages/{id}
Deletes a triage record.
Endpoint: POST /api/component_readiness/triages/{id}/force_close_regressions
Force closes the open regressions associated with a resolved triage that existed at its
resolution time (opened strictly before resolved). Force closed regressions are excluded from
the regression reuse window (regressionHysteresisDays), so they are not reopened for unrelated
failures. This prevents generic tests (for example "install should succeed") from staying open
for weeks with false "pants on fire" or "failed fix" status.
Each regression is closed at the triage's resolution time and records, directly on the regression row, that it was force closed, by which user, for what reason, and the triage that drove the action. The operation is idempotent: regressions that opened at or after the resolution time, or that are already closed, are left untouched.
The triage must be resolved. If it is not, the endpoint returns 400 Bad Request with the
message "Cannot force-close regressions for an unresolved triage. Resolve the triage first."
This is a write endpoint and requires the write_endpoints capability.
| Field | Type | Description | Required |
|---|---|---|---|
| reason | String | The reason the regressions are being force closed. | Yes |
reason is required and must be non-empty (a blank or whitespace-only value returns
400 Bad Request). A non-numeric or negative triage id in the path returns 400 Bad Request,
and a triage id that does not exist returns 404 Not Found.
| Field | Type | Description |
|---|---|---|
| closed_regression_ids | Array of number | IDs of the regressions that were open and got closed. |
| timestamp | String (time) | The closed time applied to the regressions (the resolution time). |
| links | Object | HATEOAS links (self, triage, force_close, force_close_preview). |
The regression record returned by GET /api/component_readiness/regressions/{id} includes
force_closed, force_closed_by, force_closed_reason, and force_closed_by_triage_id
directly (no join is required, the data is stored on the regression).
Endpoint: GET /api/component_readiness/triages/{id}/force_close_preview
Previews (dry run) what force_close_regressions would do for a resolved triage, without
modifying anything. Use it to review which regressions would close and to spot any that kept
failing after the claimed resolution before committing. The triage must be resolved; otherwise
the endpoint returns 400 Bad Request with the same message as the force close endpoint. A
non-numeric or negative triage id returns 400 Bad Request, and a triage id that does not
exist returns 404 Not Found.
| Field | Type | Description |
|---|---|---|
| triage_id | Number | The triage being previewed. |
| resolved | String (time) | The triage's resolution time (the cutoff used for scoping). |
| would_close | Array of object | Open regressions that opened strictly before the resolution time (would close). |
| would_not_close | Array of object | Regressions opened at or after the resolution time (left untouched). |
| links | Object | HATEOAS links (self, triage, force_close, force_close_preview). |
Each regression object in would_close / would_not_close includes:
| Field | Type | Description |
|---|---|---|
| regression_id | Number | The regression ID. |
| test_name | String | The regressed test name. |
| variants | Array of string | The regression's variants. |
| opened | String (time) | When the regression opened. |
| closed | String (time) | When the regression closed, if already closed. |
| last_failure_before_resolution | String (time) | Most recent failing job run at or before the resolution time. |
| first_failure_after_resolution | String (time) | Earliest failing job run after the resolution time, if any (a gap indicator that the test kept failing). |
| links | Object | HATEOAS links for the regression (self points to its detail endpoint). |