Skip to content

Load Testing API

The Load Testing API lets a script or a CI/CD pipeline start a saved load test, follow the run until it finishes, and read its results and its pass/fail verdict. It works for cloud tests, JMeter tests and k6 tests. Create and save the test in the dashboard first: the API runs a saved test by its name.

Every request needs your API key and, if you belong to more than one team, the id of the team that owns the test.

  • API key: copy it, or regenerate it, on the API Keys page (Account settings > API keys). The key belongs to your user and works in every team you are a member of. Treat it like a password.
  • Team id: the Default team page (Account settings > Default team) shows the team that API calls use when they do not name one, with its id, and lets you change it. The Developers page in API Monitoring shows your API key and the id of your current team side by side.

Send the key in the loadfocus-auth header and the team id in the team-id header. Without team-id, your default team is used. A wrong key, or a team you are not a member of, gets 401. A team member without access to load testing gets 403, and so does a view-only member who tries to start or stop a run or change thresholds. The API also accepts the key as an apikey query parameter, but a header keeps it out of server and proxy logs.

  • Cloud tests can be started through the API on every plan, Load Free included.
  • JMeter and k6 tests need a paid plan, or a trial of one, to start a run through the API. On Load Free the run request is refused with 400 and { "error": "Not available on the free plans. Please upgrade for API access." }. In the dashboard, Free accounts can still run them within the Free limits.
  • Listing tests, reading states, results and verdicts, and setting thresholds work on every plan.
  • The plan that counts is the team owner's, as in the dashboard.

Runs started through the API count against the same run limits as runs started in the dashboard. They also have a weekly cap for each test type: 10 runs on Load Free, 5 during a trial (25 during a Load Starter trial) and 25 on Load Starter (see Plans and limits). A refused run answers 400 with the limit it hit, for example { "error": "number-of-weekly-tests-exceeded", "window": "week", "current": 10, "maximum": 10, "retryAt": "2026-11-12T09:30:00.000Z" }, where retryAt is when the next run is allowed.

  • JMeter and k6 endpoints: 100 requests per 15 minutes per API key. Starting and stopping runs has its own allowance of 100 requests per 5 minutes per API key.
  • The cloud results analysis endpoint: 100 requests per 15 minutes per API key.
  • Every request under /api/: 10,000 per 2 minutes per IP address.

Over a limit the API answers 429. Polling a run's state every 30 seconds stays well inside these limits.

All paths start with https://loadfocus.com/api/v1/ followed by the test type: loadtests for cloud tests, jmetertests for JMeter tests and k6tests for k6 tests. A test is named by testrunname, the name you saved it under, and a run by testrunid, its run number (see What is a Test Run ID). URL-encode the name when it goes into a query string.

Action Method and path Parameters Test types
List your tests, each with its latest run GET /api/v1/{type}/ none all
Start a run of a saved test POST /api/v1/{type}/newtest/execute testrunname all
Stop a running test POST /api/v1/{type}/stop testrunname, testrunid JMeter, k6
Read a run's state GET /api/v1/{type}/state testrunname, testrunid all
Read a run's results GET /api/v1/{type}/analysis testrunname, testrunid all
Read a run's pass/fail verdict GET /api/v1/{type}/verdict testrunname, testrunid all
Read, set or clear thresholds GET, PUT, DELETE /api/v1/{type}/thresholds testrunname; for PUT the limits all
  • Start a run: for cloud tests send testrunname in the query string; for JMeter and k6 tests send it as a form field. The response does not carry the new run number, which is assigned a few seconds later. Note the latest testrunid of the test in the list before you start, then read the list again until a higher one appears. To label the run with the version you deploy, wait until its run number appears, then send testrunname, testrunid, label and optionally url as form fields to POST /api/test/{general|jmeter|k6}/run-annotation (general for cloud tests), with the same headers. releaseTag and releaseUrl on the start request only take effect when the request also carries a testrunid. See Release Tags and Run Annotations. JMeter and k6 also accept POST /api/v1/{type}/execute, which the LoadFocus API client uses.
  • Stop: send testrunname and testrunid as form fields. A cloud test cannot be stopped through the API; stop it from the dashboard.
  • State: state is running while the test runs and finished when it is done. aborted, error, failed and finished_failed_to_run mean the run ended without results.
  • Results: the Results Analysis API describes the document: percentiles, Apdex, error types, per-request and per-region numbers.
  • Verdict and thresholds: Pass/Fail Thresholds describes the limits and the verdict. Read the verdict only once the state is finished. A test without enabled thresholds returns verdict: "none".

Start a saved k6 test, then a saved cloud test:

Terminal window
curl -X POST "https://loadfocus.com/api/v1/k6tests/newtest/execute" \
-H "loadfocus-auth: YOUR_API_KEY" -H "team-id: YOUR_TEAM_ID" \
--data-urlencode "testrunname=checkout-flow"
curl -X POST "https://loadfocus.com/api/v1/loadtests/newtest/execute?testrunname=checkout-flow" \
-H "loadfocus-auth: YOUR_API_KEY" -H "team-id: YOUR_TEAM_ID"

Read the verdict of run 12 of the k6 test:

Terminal window
curl "https://loadfocus.com/api/v1/k6tests/verdict?testrunname=checkout-flow&testrunid=12" \
-H "loadfocus-auth: YOUR_API_KEY" -H "team-id: YOUR_TEAM_ID"

This workflow starts a saved k6 test, waits for the run to finish and fails the job when the verdict is a fail. Save your API key and team id as the repository secrets LOADFOCUS_API_KEY and LOADFOCUS_TEAM_ID, and set pass/fail thresholds on the test first, otherwise there is nothing to fail on. For a cloud test change k6tests to loadtests, for a JMeter test to jmetertests.

name: Load test
on:
workflow_dispatch:
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- name: Run the saved test and check its verdict
shell: bash
env:
KEY: ${{ secrets.LOADFOCUS_API_KEY }}
TEAM: ${{ secrets.LOADFOCUS_TEAM_ID }}
API: https://loadfocus.com/api/v1/k6tests
TEST: checkout-flow
run: |
H=(-sS -H "loadfocus-auth: $KEY" -H "team-id: $TEAM")
Q=$(jq -rn --arg t "$TEST" '$t|@uri')
latest() {
curl "${H[@]}" --fail-with-body "$API/" |
jq -r --arg t "$TEST" '[.[] | select(.testrunname == $t) | .testrunid | tonumber] | max // 0'
}
before=$(latest)
curl "${H[@]}" --fail-with-body -X POST "$API/newtest/execute?testrunname=$Q" \
--data-urlencode "testrunname=$TEST"
echo
# The run number is assigned a few seconds after the start request.
id=$before
for i in $(seq 30); do
sleep 10
id=$(latest)
[ "$id" -gt "$before" ] && break
done
[ "$id" -gt "$before" ] || { echo "The run did not start"; exit 1; }
# Wait up to 30 minutes for the run to finish.
state=""
for i in $(seq 60); do
state=$(curl "${H[@]}" --fail-with-body "$API/state?testrunname=$Q&testrunid=$id" | jq -r '.state // .teststate // empty')
echo "Run $id: ${state:-starting}"
case "$state" in
finished) break ;;
aborted|error|failed|finished_failed_to_run) exit 1 ;;
esac
sleep 30
done
[ "$state" = finished ] || { echo "Timed out"; exit 1; }
curl "${H[@]}" --fail-with-body "$API/verdict?testrunname=$Q&testrunid=$id" > verdict.json
jq '{verdict, checks}' verdict.json
jq -e '.verdict != "fail" and (.enabled == false or (.metricsAvailable and ((.unevaluated // []) | length == 0)))' verdict.json

The last line also fails the job when thresholds are enabled but could not be checked, for example when the run recorded no metrics, so a broken run never passes as green.

The npm package @loadfocus/loadfocus-api-client (command loadfocus-api) supports JMeter tests only. It starts a saved JMeter test, waits for it to finish and compares the results with limits you pass on the command line (--thresholds). It has no commands for k6 or cloud tests: for those, call the API directly as shown above.

Ready-made JMeter pipelines with the client: