Using the Kapptivate API, you can integrate your existing tests into your CI/CD pipeline to automatically detect regressions on your services.
By calling the continuous_integration endpoint with specific parameters in the request body, you will be able to trigger your test runs and retrieve their results directly from your pipeline.
Prerequisites
- You must have an existing Refresh Token (API key).
- You should know your Platform ID and your Test ID(s).
🔗 To learn how to create and use an API key, follow this article: How to generate and use a Kapptivate API key .
Step 1: Generate your JWT token
To use the Kapptivate API, you must include a valid JWT token in the
Authorizationheader of your requests. This JWT token is generated from your Refresh Token by calling therefresh_tokenendpoint.🔧 Important: replace
your_domain_name.kapptivate.comwith the actual domain of your kapptivate environment, that is visible on every kapptivate URL that you may see.Make sure the following header is present in your request:
Content-Type: application/json
Example request (POST):
POST https://your_domain_name.kapptivate.com/api/auth/refresh-token/ Content-Type: application/json { "refresh_token": "YOUR_API_KEY" }The response will contain your JWT token, which you will use in the
Authorizationheader of subsequent API calls. By default, this token is valid for 2 minutes.
Step 2: Trigger your test(s) from your CI/CD pipeline
To trigger one or several tests from your pipeline, you will call the
continuous_integrationendpoint.For this step, you will need:
- The Platform ID where your tests are defined.
- The Test ID(s) you want to run.
- Optionally, a variable group and some input variables.
How to find your Test ID
Open the edit panel of your test in the Kapptivate UI and copy the ID from the URL. It looks like this:
your_organization~your_product/testing/test/edit/YOUR_TEST_ID
How to find your Variable Group ID
To get the variable_group_id, open the variable group in the UI and copy the ID directly from the URL, as shown below:
Understanding the
bucketfieldThe
bucketfield on aninput_variabletells the backend which Variant of which Variable Group to use when resolving the variable value at runtime.There are two types of buckets:
Global variable — the variable is not attached to any Variable Group
{ "type": "global", "variable_group_id": null, "variant_id": null }Variable Group variable — the variable belongs to a group, and you select a specific Variant
{ "type": "variable_group", "variable_group_id": 1, "variant_id": 2 }Note: If you omit the
bucketfield for a non-global variable, the backend will automatically use the default Variant of the variable's group.Endpoint
You will use the
/api/v1/continuous_integration/endpoint with the following structure:Parameters
- name: the name of your test run (string).
-
tests: an array of test configurations. Each entry can contain:
- input_variables (optional): key/value pairs for variables required by the test, using their exact names.
- id: the ID of the test to run.
- direct_owners: the devices on which the test will run.
- options (optional): advanced options for the run.
Sample request — Simple (no variables)
POST /api/v1/continuous_integration/ Content-Type: application/json Authorization: JWT YOUR_JWT_TOKEN
{ "name": "your_test_run_name", "tests": [ { "id": 1389, "direct_owners": { "your_device": "your_device_name" } } ], "options": {} }Sample request — With global variables
Global variables are not tied to any Variable Group. You can pass their value directly. The
bucketfield is optional for global variables, but you can include it for clarity.POST /api/v1/continuous_integration/ Content-Type: application/json Authorization: JWT YOUR_JWT_TOKEN
{ "name": "your_test_run_name", "tests": [ { "id": 1389, "input_variables": { "BASE_URL": { "value": "https://api.example.com", "bucket": { "type": "global", "variable_group_id": null, "variant_id": null } }, "TIMEOUT": { "value": "30" } }, "direct_owners": { "your_device": "your_device_name" } } ], "options": {} }In this example:
-
BASE_URLis a global variable with an explicit global bucket. -
TIMEOUTis a global variable without a bucket — both forms are valid for global variables.
Sample request — With Variable Group and Variant
When your variables belong to a Variable Group, use the
bucketfield to specify which Variant (e.g. Production, Staging) to resolve the variable value from.POST /api/v1/continuous_integration/ Content-Type: application/json Authorization: JWT YOUR_JWT_TOKEN
{ "name": "your_test_run_name", "tests": [ { "id": 1389, "input_variables": { "HOST": { "value": "10.0.0.1", "bucket": { "type": "variable_group", "variable_group_id": 1, "variant_id": 2 } }, "DB_NAME": { "value": "staging_db", "bucket": { "type": "variable_group", "variable_group_id": 1, "variant_id": 2 } } }, "direct_owners": { "your_device": "your_device_name" } } ], "options": {} }In this example:
-
HOSTandDB_NAMEboth belong to Variable Group1and use Variant2(e.g. "Staging"). - The
valuefield overrides the stored value for this run. If you omitvalue, the backend will resolve it from the specified Variant.
Sample request — Let the backend resolve values from a Variant
You can omit the
valuefield and let the backend resolve the variable value from the specified Variant automatically:{ "name": "your_test_run_name", "tests": [ { "id": 1389, "input_variables": { "HOST": { "bucket": { "type": "variable_group", "variable_group_id": 1, "variant_id": 1 } }, "API_KEY": { "bucket": { "type": "variable_group", "variable_group_id": 1, "variant_id": 1 } } }, "direct_owners": { "your_device": "your_device_name" } } ], "options": {} }In this example, the backend reads the values for
HOSTandAPI_KEYfrom the Production Variant (id1) of Variable Group1.Sample request — Using the default Variant (backward compatible)
If you don't know which Variant to use, or if you are migrating from a setup without Variants, you can omit the
bucketfield entirely. The backend will use the default Variant of the variable's group:{ "name": "your_test_run_name", "tests": [ { "id": 1389, "input_variables": { "MY_INPUT_VARIABLE_NAME": "my_variable_value" }, "direct_owners": { "your_device": "your_device_name" } } ], "options": {} }This format is fully backward compatible. Existing CI/CD integrations will continue to work without changes.
Step 3: Retrieve details of your test run
When you call the
continuous_integrationendpoint, the response will contain a status, a result_uri and a result_id.Example response:
{ "status": "success", "result_uri": "/api/v1/continuous_integration/results/RESULT_ID/", "result_id": RESULT_ID }To see detailed results of your test run, perform a GET request on the
result_uri.GET /api/v1/continuous_integration/results/RESULT_ID/ Content-Type: application/json Authorization: JWT YOUR_JWT_TOKEN
The response includes:
- Name of the test run
- Status (success, failure…)
- Timing (start, end, duration)
- Number of tests and successes
{ "name": "your_test_run_name", "result": { "status": "success", "timing": { "end": "2021-03-15T15:15:49.39303055Z", "start": "2021-03-15T15:15:47.597870374Z", "duration": 1.795160021 }, "nb_tests": 1, "nb_success": 1 } }
Step 4: Full API usage example (generic Bash script)
-
This example shows how to:
- Retrieve a JWT token from your refresh token
- Trigger a CI test run using the
continuous_integrationendpoint - (Optional) Clean large fields from the JSON output
- Fetch the final result using
result_uri
🔧 Important: Replace
your_domain_name.kapptivate.comwith the actual domain of your kapptivate workspace.Reusable Bash script:
#!/bin/bash set -euo pipefail # 1) Get a fresh JWT token curl -s -X POST -H "Content-Type: application/json" \ -d "{\"refresh_token\": \"YOUR_REFRESH_TOKEN\"}" \ https://your_domain_name.kapptivate.com/api/auth/refresh-token/ \ /tmp/api_auth.json Auth_Bearer=$(jq -r ".token" /tmp/api_auth.json) if [ -z "$Auth_Bearer" ] || [ "$Auth_Bearer" = "null" ]; then echo "Failed to retrieve JWT token" exit 1 fi echo "JWT token retrieved successfully." # 2) Trigger a CI test run curl --fail --location --request POST \ "https://your_domain_name.kapptivate.com/api/v1/continuous_integration/" \ --header "Content-Type: application/json;charset=UTF-8" \ --header "Authorization: JWT $Auth_Bearer" \ -d "@/path/to/your/body.json" \ /tmp/test_result_raw.json echo "Test triggered successfully." # 3) (Optional) Clean the JSON output jq "del( .. | .screenshot_url_before?, .. | .screenshot_url_after?, .. | .time_since_parent_start? )" \ /tmp/test_result_raw.json \ /tmp/test_result.json echo "Clean JSON saved." # 4) Retrieve final results Result_URI=$(jq -r ".result_uri" /tmp/test_result_raw.json) if [ -n "$Result_URI" ] && [ "$Result_URI" != "null" ]; then curl --fail --location --request GET \ "https://your_domain_name.kapptivate.com${Result_URI}" \ --header "Content-Type: application/json;charset=UTF-8" \ --header "Authorization: JWT $Auth_Bearer" \ /tmp/final_test_result.json echo "Final test results saved." else echo "No result_uri found in the API response." exit 1 fiNotes
- Replace your_domain_name.kapptivate.com with your real environment URL.
- Replace YOUR_REFRESH_TOKEN with your actual API refresh token.
-
body.jsonmust contain your CI payload (tests, devices, variables, etc.). -
result_uripoints to the endpoint providing the final execution result.