Skip to content

Durations API

The Durations API returns a predicted duration for every test, so a test runner can split shards by duration instead of by test count. A balanced split makes the slowest shard shorter and CI finishes faster.

You send Flakiness.io the list of tests you are about to run, and it returns the same list annotated with each test’s predicted duration. The runner reads those durations and balances its shards.

The exchange consists of three sequential steps:

  1. Create Session - Start a durations session for a commit and receive a testDurationsToken plus a presigned uploadUrl.
  2. Upload the Test List - Upload a Flakiness report describing the tests you intend to run, using the presigned URL.
  3. Submit & Poll - Trigger the computation, receive a presigned downloadUrl, and poll it until the report with durations attached is ready.

For each test, Flakiness.io returns a predicted duration per environment, based on how that test has run before.

A test with no prior data still appears in the response, but with an empty attempts array; likewise, a test that has data for some environments but not others simply has no attempt for the environments it lacks. So a missing prediction shows up as a missing attempt, not a missing test. Treat any test or environment with no attempt as “no estimate” and substitute your own (for example, the test count). Otherwise new tests land at zero duration and unbalance the shards.

Identifies the commit you are testing. Together with the shardGroupKey, it keeps the predicted durations stable and consistent across every shard of a run.

Every shard in a run asks for the same durations. The shardGroupKey groups those concurrent requests so the prediction is computed once and shared, rather than recomputed by each shard. It is combined with the commitId, so the test runner’s name and version is usually enough.

Both the upload and the download use the Flakiness.io JSON Report format. The report you upload lists the tests and the environment(s) they will run in. The report you download is the same document with each test’s attempts filled in: one attempt per environment for which a prediction exists, carrying the predicted duration. Every uploaded test is present in the response; tests without a prediction keep an empty attempts array.

Like the Upload API, both the upload and the download are Brotli-compressed with Content-Type: application/json and Content-Encoding: br.

  1. Create a Durations Session

    Start the session for the commit you are about to test:

    Terminal window
    curl -X POST "https://flakiness.io/api/testDurations/create" \
    -H "Authorization: Bearer $FLAKINESS_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"commitId":"a1b2c3d","shardGroupKey":"ci-run-8123"}'

    Response:

    {
    "testDurationsToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "uploadUrl": "https://s3.flakiness.test/flakiness-data/test-durations/..."
    }

    The testDurationsToken authenticates the submit step and expires in 10 minutes.

  2. Compress and Upload the Test List

    Build a Flakiness report listing the tests you are about to run and the environment(s) they run in, then compress it with Brotli:

    Terminal window
    brotli --quality=9 --output=tests.json.br tests.json

    Upload it to the presigned URL:

    Terminal window
    curl -X PUT "$UPLOAD_URL" \
    -H "Content-Type: application/json" \
    -H "Content-Encoding: br" \
    --data-binary @tests.json.br
  3. Submit and Receive a Download URL

    Trigger the computation with the session token:

    Terminal window
    curl -X POST "https://flakiness.io/api/testDurations/submit" \
    -H "Authorization: Bearer $TEST_DURATIONS_TOKEN"

    Response:

    {
    "downloadUrl": "https://s3.flakiness.test/flakiness-data/test-durations/..."
    }

    The downloadUrl is valid for 1 hour.

  4. Poll the Download URL

    The report is computed asynchronously, so the downloadUrl is not ready the instant submit returns. Poll it until it responds with the report, usually within a few seconds. The URL returns 404 while the result is still being computed:

    Terminal window
    until curl -fsS --compressed "$DOWNLOAD_URL" -o durations.json; do sleep 1; done

    Each test in durations.json now carries an attempt per environment for which a prediction exists, with the predicted duration in milliseconds. Tests with no prediction keep an empty attempts array, so fall back to your own estimate for those. Feed the durations into your runner to balance shards.

| Method | Endpoint | Authorization | Content-Type | |--------|----------|---------------|--------------| | POST | /api/testDurations/create | Bearer {ACCESS_TOKEN} | application/json |

Starts a durations session and returns a session token along with a presigned URL for uploading the test list.

Request Body:

  • commitId - The commit you are testing. Combined with shardGroupKey, it keeps predictions stable across a run’s shards. It is not used to look up history.
  • shardGroupKey - Groups concurrent requests from the shards of one run so the prediction is computed once. Combined with commitId, so the test runner’s name and version is usually enough. Must match ^[a-zA-Z0-9_-]+$ and be 1–250 characters.
  • orgSlug, projectSlug - Optional. When the access token is already bound to a single project (CI access token or GitHub OIDC), these are inferred and can be omitted.

Response Fields:

  • testDurationsToken - JWT for authenticating the submit call. Expires in 10 minutes.
  • uploadUrl - Presigned URL for uploading the Brotli-compressed test list.

| Method | Endpoint | Authorization | Content-Type | |--------|----------|---------------|--------------| | POST | /api/testDurations/submit | Bearer {TEST_DURATIONS_TOKEN} | N/A |

Triggers the computation for the uploaded test list and returns a presigned URL for the annotated report. Call this after the test list has been uploaded to the uploadUrl from the create step.

The report is produced asynchronously, so the downloadUrl is not populated when this call returns. Poll the URL until it responds with 200, usually within a few seconds; it returns 404 while the result is still being computed. The annotated report is a Brotli-compressed Flakiness report where each test carries an attempt per environment for which a prediction exists; tests without a prediction keep an empty attempts array.

Response Fields:

  • downloadUrl - Presigned URL for the annotated report. Poll it until ready. Valid for 1 hour.