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:
objectSynchronous client for the Lynqa REST API.
Wraps every API endpoint in a typed Python method. All network calls use a shared
requests.Sessionso 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 usehttpsso the API key is never sent in clear text; plainhttpis only accepted for loopback hosts (localhost,127.0.0.1,::1).timeout – Per-request network timeout in seconds (connect + read). Defaults to
30. PassNoneto disable (not recommended). Can be overridden per call via thetimeoutkeyword.
- Raises:
ValueError – If
base_urlis nothttps(and not a loopbackhttpaddress).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, andThensteps.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 aCreateGherkinTest(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
sequentialisTrue. Defaults toFalse.
- 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:
LynqaClientError –
401authentication failed,404if not found,429rate 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:
LynqaClientError –
401on authentication failure,429rate limit.
- get_purchases() list
List credit purchase history for this API key.
Corresponds to
GET /organization/purchases.- Returns:
List of purchase records.
- Raises:
LynqaClientError –
401on authentication failure,429rate 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:
LynqaClientError –
401authentication failed,404if not found,410if the run expired,429rate 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:
LynqaClientError –
401on authentication failure,429rate 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
webhookslist where each entry reports the deliveryurl, HTTP statuscode, and anerrorstring (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:
LynqaClientError –
401authentication failed,404if not found,410if expired,429rate 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 astepStatuseslist where each entry is aStepReport-shaped dict containing the commands executed, timestamps, assertions report, verdict cause, or error. Pass an entry topylynqa.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:
LynqaClientError –
401authentication failed,404if not found,410if expired,429rate 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 ofwaiting,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:
LynqaClientError –
401authentication failed,404if not found,410if expired,429rate 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 withname, optionalvalue,htmlElement, andscreenshot(UUID).start/end(str, ISO 8601) - present once the step has started / finished.assertionsReport(dict) - present forsuccessorfailedsteps; contains individual assertion checks and a screenshot UUID.testVerdictCause(str) - human-readable failure reason, present whenstatusisfailed.error(str) - present whenstatusiserror.
- Parameters:
test_run_id – ID of the test run.
step_index – Zero-based index of the step to retrieve.
- Returns:
Step report dict.
- Raises:
LynqaClientError –
401authentication failed,404if not found,429rate 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
nextCursorin a previous response).limit – Maximum number of results to return.
filters – Filter criteria. Pass a
TestRunsFilterto narrow results by status, date range, API key, or run IDs. All fields are optional; omit to return all runs.
- Returns:
Dict containing
testRunsand an optionalnextCursorfor pagination.- Raises:
LynqaClientError –
400if the query is malformed,401authentication failed,429rate 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:
LynqaClientError –
400if body is malformed,401,429.
Example:
result = client.stop_test_runs(["mf4zz9945nwbofv81shozwb5", "zcuk4l13zax1piz2h73imct6"]) print(result["stoppedTestRunIds"]) # ["mf4zz9945nwbofv81shozwb5"]