Client module

Lynqa API Client.

Python client for the Lynqa API.

Lynqa is a manual test execution service. This module provides a thin, synchronous wrapper around the REST API, covering test run management, step inspection, screenshot retrieval, and organization operations.

Authentication

Every request is authenticated with an API key passed in the x-api-key HTTP header. Keys are created at https://my.lynqa.smartesting.com/integration.

Quick start:

from lynqa import CreateTestStep, LynqaClient

client = LynqaClient(api_key="your-api-key")

run_id = client.add_test_run(
    url="https://example.com",
    steps=[
        CreateTestStep(
            action='Click on the "Login" button',
            expected_result="The user is logged in",
        ),
    ],
    name="Smoke - login",
)

status = client.get_test_run_status(run_id)
print(status["status"])  # e.g. "running"
class pylynqa.client.LynqaClient(api_key: str, base_url: str = 'https://api.lynqa.smartesting.com', timeout: float | tuple[float, float] | None = 30.0)

Bases: object

Synchronous client for the Lynqa REST API.

Wraps every API endpoint in a typed Python method. All network calls use a shared requests.Session so that TCP connections are reused across requests.

Parameters:
  • api_key – Lynqa API key.

  • base_url – Base URL of the API. Defaults to the production server https://api.lynqa.smartesting.com. Override for self-hosted or staging environments. Must use https so the API key is never sent in clear text; plain http is only accepted for loopback hosts (localhost, 127.0.0.1, ::1).

  • timeout – Per-request network timeout in seconds (connect + read). Defaults to 30. Pass None to disable (not recommended). Can be overridden per call via the timeout keyword.

Raises:
  • ValueError – If base_url is not https (and not a loopback http address).

  • LynqaClientError – On any non-2xx response from the API.

Example:

client = LynqaClient(api_key="lq_live_xxxxxxxxxxxx")
print(client.get_test_execution_credits())  # 410
add_gherkin_test_run(url: str, scenario: str, *, name: str | None = None, context: TestRunContext | None = None, guidance: list[TextualData] | None = None, attachments: list[CreateAttachment] | None = None, webhooks: list[str] | None = None) str

Execute a Gherkin (BDD) test run.

Corresponds to POST /testRuns/gherkin.

Parameters:
  • url – URL of the system under test.

  • scenario – Full Gherkin scenario text, including Given, When, and Then steps.

  • name – Optional human-readable name for this run.

  • context – Optional locale and secrets context.

  • guidance – Optional global guidance hints for the agent.

  • attachments – Optional files attached to the test run (base64-encoded).

  • webhooks – Optional list of webhook URLs to notify once the test run has ended.

Returns:

The ID assigned to the new test run.

Raises:

LynqaClientError – On API errors (400, 401, 403, 422, 429).

Example:

run_id = client.add_gherkin_test_run(
    url="https://example.com",
    scenario=(
        "Given the user is on the login page\\n"
        "When the user enters valid credentials\\n"
        "Then the user is redirected to the dashboard"
    ),
    name="Login - Gherkin",
    webhooks=["https://my-webhook.com/test-result"],
)
add_test_batch(tests: list[CreateTest | CreateGherkinTest], *, sequential: bool = False, stop_on_failure: bool = False) list[str]

Execute a batch of manual and/or Gherkin tests in a single request.

Corresponds to POST /testRuns/batch.

Parameters:
  • tests – Tests to execute. Each entry is a CreateTest (manual) or a CreateGherkinTest (Gherkin).

  • sequential – Whether the tests are executed sequentially (True) or in parallel (False, the default).

  • stop_on_failure – Whether to skip the remaining tests as soon as one fails. Only meaningful when sequential is True. Defaults to False.

Returns:

The IDs assigned to the created test runs, in request order.

Raises:

LynqaClientError – On API errors (400, 401, 403, 422, 429).

Example:

run_ids = client.add_test_batch(
    [
        CreateTest(
            url="https://example.com",
            steps=[CreateTestStep(action='Click on "Login"')],
        ),
        CreateGherkinTest(
            url="https://example.com",
            scenario="Given the user is logged in\\nThen the dashboard is shown",
        ),
    ],
    sequential=True,
    stop_on_failure=True,
)
add_test_run(url: str, steps: list[CreateTestStep], *, name: str | None = None, context: TestRunContext | None = None, guidance: list[TextualData] | None = None, attachments: list[CreateAttachment] | None = None, webhooks: list[str] | None = None) str

Execute a manual test run.

Corresponds to POST /testRuns.

Parameters:
  • url – URL of the system under test, e.g. 'https://my-app.example.com'.

  • steps – Ordered list of test steps to execute.

  • name – Optional human-readable name for this run.

  • context – Optional locale and secrets context.

  • guidance – Optional global guidance hints for the agent.

  • attachments – Optional files attached to the test run (base64-encoded).

  • webhooks – Optional list of webhook URLs to notify once the test run has ended.

Returns:

The ID assigned to the new test run.

Raises:

LynqaClientError – On API errors (400, 401, 403, 422, 429).

Example:

run_id = client.add_test_run(
    url="https://example.com",
    steps=[
        CreateTestStep(
            action='Fill in the username field with "admin"',
            expected_result="The username field shows 'admin'",
        ),
        CreateTestStep(action='Click on "Submit"'),
    ],
    name="Login - happy path",
    webhooks=["https://my-webhook.com/test-result"],
)
delete_test_run(test_run_id: str) None

Delete a test run.

Corresponds to DELETE /testRuns/{testRunId}.

Parameters:

test_run_id – ID of the test run to delete.

Raises:

LynqaClientError401 authentication failed, 404 if not found, 429 rate limit.

get_changelog_formatted(releases_count: int) str

Get the formatted changelog for the most recent releases.

Corresponds to GET /changelog/formatted.

Parameters:

releases_count – Number of releases to fetch.

Returns:

The formatted changelog.

get_changelog_raw() str

Get the raw changelog in Markdown format.

Corresponds to GET /changelog/raw.

Returns:

The changelog as a Markdown string.

get_credit_ledger() list

Get the full credit ledger (all credit debits and credits) for this API key.

Corresponds to GET /organization/creditLedger.

Returns:

List of ledger entries.

Raises:

LynqaClientError401 on authentication failure, 429 rate limit.

get_purchases() list

List credit purchase history for this API key.

Corresponds to GET /organization/purchases.

Returns:

List of purchase records.

Raises:

LynqaClientError401 on authentication failure, 429 rate limit.

get_screenshot(test_run_id: str, screenshot_id: str) str

Retrieve a screenshot as a base64-encoded string.

Screenshot UUIDs are embedded in step reports and the initial report. Corresponds to GET /testRuns/{testRunId}/screenshots/{screenshotId}.

Parameters:
  • test_run_id – ID of the test run the screenshot belongs to.

  • screenshot_id – UUID of the screenshot.

Returns:

Base64-encoded PNG data.

Raises:

LynqaClientError401 authentication failed, 404 if not found, 410 if the run expired, 429 rate limit.

Example:

import base64

data = client.get_screenshot(run_id, "4b111ba4-c236-4770-67bf-0f17d0230e47")
with open("screenshot.png", "wb") as f:
    f.write(base64.b64decode(data))
get_test_execution_credits() int

Get the number of test execution credits available for this API key.

Corresponds to GET /organization/credits.

Returns:

Remaining credit count.

Raises:

LynqaClientError401 on authentication failure, 429 rate limit.

get_test_run(test_run_id: str) dict

Retrieve a test run together with its steps.

Corresponds to GET /testRuns/{testRunId}.

The response is either a manual test (type = 'manual') or a Gherkin test (type = 'gherkin').

When webhooks were declared at creation time, the response includes a webhooks list where each entry reports the delivery url, HTTP status code, and an error string (if the delivery failed).

Parameters:

test_run_id – ID of the test run to retrieve.

Returns:

Test run dict including url, type, steps, and, when applicable, webhooks.

Raises:

LynqaClientError401 authentication failed, 404 if not found, 410 if expired, 429 rate limit.

get_test_run_full_status(test_run_id: str) dict

Get the full status of a test run, including per-step reports.

Corresponds to GET /testRuns/{testRunId}/fullStatus.

Extends get_test_run_status() with a stepStatuses list where each entry is a StepReport-shaped dict containing the commands executed, timestamps, assertions report, verdict cause, or error. Pass an entry to pylynqa.models.StepReport.from_dict() to obtain a typed object.

Parameters:

test_run_id – ID of the test run.

Returns:

Full status dict including stepStatuses (a list of step report dicts).

Raises:

LynqaClientError401 authentication failed, 404 if not found, 410 if expired, 429 rate limit.

get_test_run_status(test_run_id: str) dict

Get the overall status of a test run.

Corresponds to GET /testRuns/{testRunId}/status.

The returned dict contains:

  • createdAt (str, ISO 8601) - when the test run was created.

  • status (str) - one of waiting, running, success, failed, error, stopped, not_run.

  • start / end (str, ISO 8601) - timing information.

  • expiration (str, ISO 8601) - when the run data will be purged.

  • initialReport (dict) - screenshot UUID captured before step 1, and an optional startup error (e.g. host_not_reachable).

Parameters:

test_run_id – ID of the test run.

Returns:

Status dict.

Raises:

LynqaClientError401 authentication failed, 404 if not found, 410 if expired, 429 rate limit.

get_test_run_step_status(test_run_id: str, step_index: int) dict

Get the status report of a specific step within a test run.

Corresponds to GET /testRuns/{testRunId}/testSteps/{stepIndex}.

The returned dict contains:

  • status (str) - step execution status.

  • commands (list) - browser commands executed during this step, each with name, optional value, htmlElement, and screenshot (UUID).

  • start / end (str, ISO 8601) - present once the step has started / finished.

  • assertionsReport (dict) - present for success or failed steps; contains individual assertion checks and a screenshot UUID.

  • testVerdictCause (str) - human-readable failure reason, present when status is failed.

  • error (str) - present when status is error.

Parameters:
  • test_run_id – ID of the test run.

  • step_index – Zero-based index of the step to retrieve.

Returns:

Step report dict.

Raises:

LynqaClientError401 authentication failed, 404 if not found, 429 rate limit.

health_live() dict

Check whether the API service is alive.

Corresponds to GET /health/live.

Returns:

Server response body.

health_ready() dict

Check whether the API service is ready to accept requests.

Corresponds to GET /health/ready.

Returns:

Server response body.

query_test_runs(cursor: int | None = None, limit: int | None = None, filters: TestRunsFilter | None = None) dict

List paginated test runs matching the given filters.

Corresponds to POST /testRuns/query.

Parameters:
  • cursor – Return runs starting from this cursor ID (from nextCursor in a previous response).

  • limit – Maximum number of results to return.

  • filters – Filter criteria. Pass a TestRunsFilter to narrow results by status, date range, API key, or run IDs. All fields are optional; omit to return all runs.

Returns:

Dict containing testRuns and an optional nextCursor for pagination.

Raises:

LynqaClientError400 if the query is malformed, 401 authentication failed, 429 rate limit.

Example:

page = client.query_test_runs(
    filters=TestRunsFilter(
        statuses=["failed"],
        relative_period=TimePeriod(count=24, unit="h"),
    ),
    limit=50,
)
for run in page["testRuns"]:
    print(run["id"], run["status"])
stop_test_runs(test_run_ids: list[str]) dict

Request cancellation of one or more running test executions.

Corresponds to POST /testRuns/stop.

Parameters:

test_run_ids – List of test run IDs to stop.

Returns:

Dict with stoppedTestRunIds - the IDs that were successfully scheduled for stopping.

Raises:

LynqaClientError400 if body is malformed, 401, 429.

Example:

result = client.stop_test_runs(["mf4zz9945nwbofv81shozwb5", "zcuk4l13zax1piz2h73imct6"])
print(result["stoppedTestRunIds"])  # ["mf4zz9945nwbofv81shozwb5"]