REST API Documentation

Programmatic access to QualityGraph — manage user journeys, test cases, test runs, and more via the REST API.

Base URL: https://qualitygraph.harnessqa.dev/api

Authentication

All API requests require authentication via an API token. Tokens are created from the Settings page in the dashboard.

Include your token in the Authorization header:

terminal
curl -H "Authorization: Bearer qg_your_token_here" \
  https://qualitygraph.harnessqa.dev/api/tms/journeys?orgId=YOUR_ORG_ID

Security: API tokens grant access to all resources within the organization they were created for. Keep them secret — do not commit tokens to version control. Use environment variables or secret managers in CI/CD.

API Tokens

Everything the dashboard does, a token can do.

A token acts as the user who created it, inside one organization: test cases, journeys, runs, releases, runbooks, repositories, coverage, health, trends, flaky tests, pull-request risk and test gaps, quality gates, members and invitations, result ingestion and CLI uploads. Requests for another organization answer 403; the platform admin area is session-only. Revoking the token ends its access immediately.

Create and manage API tokens. Tokens are scoped to an organization and can optionally expire.

Create a token

Navigate to Settings in the dashboard and click Create Token. You'll be shown the full token once — copy it immediately.

Token format

All API tokens are prefixed with qg_ followed by 64 hex characters:

qg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Using tokens in CI/CD

Store your token as an environment variable and reference it in scripts:

yaml
# GitHub Actions example
env:
  QG_TOKEN: ${{ secrets.QUALITYGRAPH_TOKEN }}

steps:
  - name: Create user journey
    run: |
      curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/journeys" \
        -H "Authorization: Bearer $QG_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"orgId":"YOUR_ORG_ID","title":"Checkout Flow","steps":[]}'

Response Format

All responses are wrapped in a standard envelope:

response envelope
{
  "data": { ... },
  "meta": {
    "timestamp": "2026-09-05T12:00:00.000Z"
  }
}

List endpoints return arrays in data. Single-resource endpoints return objects. Error responses follow the same envelope with an error field.

User Journeys

User journeys represent critical user flows in your application. Each journey has a sequence of steps (action + expected outcome) and can be linked to test cases to track coverage.

GET
/tms/journeys?orgId=:orgId

List user journeys. Filters: folderId, includeSubfolders=true (with folderId), unfiled=true

GET
/tms/journeys/:id

Get a single journey with linked test cases

POST
/tms/journeys

Create a new user journey; folderId files it into a folder

PATCH
/tms/journeys/:id

Update a user journey; folderId moves it (null = unfiled)

DELETE
/tms/journeys/:id

Delete a user journey

POST
/tms/journeys/:id/cases

Link test cases to a journey

DELETE
/tms/journeys/:id/cases/:caseId

Unlink a test case from a journey

GET
/tms/journeys/export?orgId=:orgId

Download journeys as a file. format=json (default) or csv; folderId (+ includeSubfolders=true), unfiled=true, ids=a,b,c, status, priority, search narrow it

POST
/tms/journeys/import

Import journeys from JSON or CSV: { orgId, content, format?, targetFolderId?, onDuplicate?: skip|update|create, dryRun? }

Journey folders

Journeys live in folders that nest to any depth through parentId. Moving a folder into its own subtree is refused. Deleting a folder keeps its journeys (they become unfiled) and lifts its subfolders one level.

GET
/tms/journey-folders?orgId=:orgId

List folders (flat, each with parentId, childrenCount and journeyCount)

POST
/tms/journey-folders

Create: { orgId, title, description?, parentId? }

PATCH
/tms/journey-folders/:id

Rename ({ title }) or move ({ parentId } — null for the top level)

DELETE
/tms/journey-folders/:id

Delete a folder; journeys inside become unfiled

terminal
# A folder inside another, then a journey filed into it
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/journey-folders" \
  -H "Authorization: Bearer $QG_TOKEN" -H "Content-Type: application/json" \
  -d '{ "orgId": "YOUR_ORG_ID", "title": "Checkout", "parentId": "SHOPPING_FOLDER_ID" }'

curl -X PATCH "https://qualitygraph.harnessqa.dev/api/tms/journeys/JOURNEY_ID" \
  -H "Authorization: Bearer $QG_TOKEN" -H "Content-Type: application/json" \
  -d '{ "folderId": "CHECKOUT_FOLDER_ID" }'

# Everything under Shopping, subfolders included
curl -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/journeys?orgId=YOUR_ORG_ID&folderId=SHOPPING_FOLDER_ID&includeSubfolders=true"

List journeys

terminal
curl -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/journeys?orgId=YOUR_ORG_ID"

Create a journey

terminal
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/journeys" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orgId": "YOUR_ORG_ID",
    "title": "User Checkout Flow",
    "description": "Complete purchase flow from cart to confirmation",
    "priority": "HIGH",
    "status": "ACTIVE",
    "tags": ["checkout", "payment", "critical"],
    "steps": [
      {"order": 1, "action": "Add item to cart", "expectedOutcome": "Item appears in cart with correct price"},
      {"order": 2, "action": "Proceed to checkout", "expectedOutcome": "Checkout form displays with cart summary"},
      {"order": 3, "action": "Enter payment details", "expectedOutcome": "Payment form validates input"},
      {"order": 4, "action": "Submit order", "expectedOutcome": "Order confirmation page with order ID"}
    ]
  }'

Response

json
{
  "data": {
    "id": "a1b2c3d4-...",
    "title": "User Checkout Flow",
    "description": "Complete purchase flow from cart to confirmation",
    "priority": "HIGH",
    "status": "ACTIVE",
    "tags": ["checkout", "payment", "critical"],
    "steps": [
      {"order": 1, "action": "Add item to cart", "expectedOutcome": "Item appears in cart with correct price"},
      {"order": 2, "action": "Proceed to checkout", "expectedOutcome": "Checkout form displays with cart summary"},
      {"order": 3, "action": "Enter payment details", "expectedOutcome": "Payment form validates input"},
      {"order": 4, "action": "Submit order", "expectedOutcome": "Order confirmation page with order ID"}
    ],
    "orgId": "YOUR_ORG_ID",
    "createdAt": "2026-09-05T12:00:00.000Z",
    "updatedAt": "2026-09-05T12:00:00.000Z"
  }
}

Update a journey

terminal
curl -X PATCH "https://qualitygraph.harnessqa.dev/api/tms/journeys/JOURNEY_ID" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"priority": "CRITICAL", "status": "ACTIVE"}'

Link test cases to a journey

terminal
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/journeys/JOURNEY_ID/cases" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"testCaseIds": ["case-id-1", "case-id-2"]}'

Export and import journeys

An export carries folders as paths (Shopping / Checkout) and linked test cases by name, never by id, so it can be imported into any organization. Import creates missing folders, links test cases whose names match, and matches duplicates by title within the same folder. dryRun: true validates the file and reports what would happen without writing anything.

terminal
# JSON export of one folder and everything under it
curl -o journeys.json -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/journeys/export?orgId=YOUR_ORG_ID&folderId=SHOPPING_FOLDER_ID&includeSubfolders=true"

# CSV export: Folder,Title,Description,Steps,Priority,Status,Tags,Test Cases
curl -o journeys.csv -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/journeys/export?orgId=YOUR_ORG_ID&format=csv"

# Import under a folder; the file contents travel in the JSON body
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/journeys/import" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg c "$(cat journeys.csv)" '{orgId: "YOUR_ORG_ID", content: $c, targetFolderId: "IMPORTED_FOLDER_ID", onDuplicate: "skip"}')"

# → { "format": "csv", "total": 12, "created": 10, "updated": 0, "skipped": 2, "foldersCreated": 3, "linked": 7, "errors": [], "warnings": [] }

Journey object fields

FieldTypeDescription
orgIdstring (UUID)Organization ID (required)
titlestringJourney name (required)
descriptionstringDetailed description
stepsarraySteps with order, action, expectedOutcome
prioritystringLOW, MEDIUM, HIGH, or CRITICAL
statusstringACTIVE, DRAFT, or DEPRECATED
tagsstring[]Arbitrary tags for filtering

Test Suites

Test suites are the folders of the Test Cases tab. They nest to any depth via the parentId field; a suite cannot be moved into its own subtree. Deleting a suite keeps its cases (they become unfiled) and lifts its subfolders one level.

GET
/tms/suites?orgId=:orgId

List suites (flat, each with parentId, childrenCount and testCaseCount)

POST
/tms/suites

Create: { orgId, title, description?, parentId? }

PATCH
/tms/suites/:id

Rename ({ title }) or move ({ parentId } — null for the top level)

DELETE
/tms/suites/:id

Delete a suite; cases inside become unfiled

Create a suite

terminal
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/suites" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orgId": "YOUR_ORG_ID",
    "title": "Authentication Tests",
    "description": "All test cases related to user authentication"
  }'

Test Cases

Individual test cases with steps, preconditions, and metadata. Can be linked to suites and user journeys.

GET
/tms/cases?orgId=:orgId

List test cases. Filters: suiteId, includeSubfolders=true (with suiteId), unfiled=true, status, priority, search; page, limit (max 100)

GET
/tms/cases/:id

Get a test case with execution history

POST
/tms/cases

Create a test case

POST
/tms/cases/bulk

Bulk create test cases

PATCH
/tms/cases/:id

Update a test case; suiteId moves it between folders (null = unfiled)

DELETE
/tms/cases/:id

Delete a test case

POST
/tms/cases/bulk-delete

Delete several test cases: { ids: [...] }

GET
/tms/cases/export?orgId=:orgId

Download test cases as a file. format=json (default) or csv; folderId (+ includeSubfolders=true), unfiled=true, ids=a,b,c, status, priority, search narrow it

POST
/tms/cases/import

Import test cases from JSON or CSV: { orgId, content, format?, targetFolderId?, onDuplicate?: skip|update|create, dryRun? }

Export and import test cases

JSON exports are lossless and versioned (format: "qualitygraph-test-cases", version: 1). CSV exports have the columns Folder, Name, Description, Preconditions, Steps, Priority, Type, Test Type, Status, Tags, Estimated Minutes, Journey; steps are written one per line as 1. action => expected and tags are separated by semicolons. On import, headers from other tools are understood as well (Section, Title, Expected Result, Labels, Automation Type, Estimate…), folder paths are created undertargetFolderId, and a case whose name already exists in the same folder is skipped, updated or duplicated according to onDuplicate. Rows that cannot be imported are reported with their line number; the rest still go in. Up to 5,000 rows per call.

terminal
# Export the cases you can see in a folder, as a spreadsheet
curl -o cases.csv -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/cases/export?orgId=YOUR_ORG_ID&format=csv&folderId=SUITE_ID&includeSubfolders=true"

# Preview an import without writing anything
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/cases/import" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg c "$(cat cases.csv)" '{orgId: "YOUR_ORG_ID", content: $c, dryRun: true}')"

# Then import for real, updating cases that already exist
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/cases/import" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg c "$(cat cases.csv)" '{orgId: "YOUR_ORG_ID", content: $c, onDuplicate: "update"}')"

# → { "format": "csv", "total": 40, "created": 35, "updated": 5, "skipped": 0, "foldersCreated": 4, "linked": 12,
#     "errors": [{ "row": 17, "message": "Name is required" }], "warnings": [] }

Create a test case

terminal
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/cases" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orgId": "YOUR_ORG_ID",
    "name": "Login with valid credentials",
    "description": "Verify user can login with correct email and password",
    "priority": "HIGH",
    "caseType": "MANUAL",
    "suiteId": "SUITE_ID",
    "journeyId": "JOURNEY_ID",
    "steps": [
      {"stepNumber": 1, "action": "Navigate to /login", "expected": "Login form displayed"},
      {"stepNumber": 2, "action": "Enter valid email and password", "expected": "Fields populated"},
      {"stepNumber": 3, "action": "Click Sign In", "expected": "Redirected to dashboard"}
    ],
    "tags": ["auth", "login", "smoke"]
  }'

Bulk create test cases

terminal
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/cases/bulk" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cases": [
      {"orgId": "YOUR_ORG_ID", "name": "Login success", "priority": "HIGH"},
      {"orgId": "YOUR_ORG_ID", "name": "Login invalid password", "priority": "MEDIUM"},
      {"orgId": "YOUR_ORG_ID", "name": "Login rate limit", "priority": "LOW"}
    ]
  }'

Query parameters for listing

ParamTypeDescription
orgIdstringFilter by organization
suiteIdstringFilter by test suite
statusstringACTIVE, DRAFT, DEPRECATED
prioritystringLOW, MEDIUM, HIGH, CRITICAL
searchstringSearch by name
pagenumberPage number (default: 1)
limitnumberItems per page (default: 50)

Test Runs

A test run is an execution session — a collection of test case results. Create a run, then submit results for each test case.

GET
/tms/runs?orgId=:orgId

List test runs

GET
/tms/runs/:id

Get a test run with all results

POST
/tms/runs

Create a test run

PATCH
/tms/runs/:id

Update a test run (status, etc.)

POST
/tms/runs/:id/results

Submit test execution results

DELETE
/tms/runs/:id

Delete a test run

Create a run and submit results

terminal
# 1. Create a test run
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/runs" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orgId": "YOUR_ORG_ID",
    "title": "Nightly Regression - 2026-09-05",
    "environment": "staging"
  }'

# Response: {"data": {"id": "RUN_ID", ...}}

# 2. Submit results
curl -X POST "https://qualitygraph.harnessqa.dev/api/tms/runs/RUN_ID/results" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "results": [
      {"testCaseId": "CASE_1", "status": "PASSED", "duration": 1.2},
      {"testCaseId": "CASE_2", "status": "FAILED", "duration": 3.5, "notes": "Timeout on payment API"},
      {"testCaseId": "CASE_3", "status": "SKIPPED"}
    ]
  }'

# 3. Complete the run
curl -X PATCH "https://qualitygraph.harnessqa.dev/api/tms/runs/RUN_ID" \
  -H "Authorization: Bearer $QG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "COMPLETED"}'

Result statuses

PASSEDFAILEDSKIPPEDBLOCKED

Releases & Runbooks

Group test runs into releases and keep operational procedures next to them. Descriptions, notes and step instructions accept Markdown.

GET
/tms/releases?orgId=:orgId

List releases with run roll-ups (status, tag, search filters)

POST
/tms/releases

Create a release: { orgId, name, version?, description?, targetDate?, notes?, tags? }

GET
/tms/releases/:id

Release with its test runs and pass/fail totals

PATCH
/tms/releases/:id

Update fields or status (PLANNED, IN_PROGRESS, RELEASED, CANCELLED)

DELETE
/tms/releases/:id

Delete a release; its runs are kept

POST
/tms/releases/:id/runs

Attach runs: { runIds: [...] }

DELETE
/tms/releases/:id/runs/:runId

Detach a run

GET
/tms/runbooks?orgId=:orgId

List runbooks (category, status, tag, search filters)

POST
/tms/runbooks

Create: { orgId, title, category, description?, steps: [{ order, title, instruction?, command? }], tags? }

GET
/tms/runbooks/:id

Runbook with steps

PATCH
/tms/runbooks/:id

Update fields, steps or status

DELETE
/tms/runbooks/:id

Delete a runbook

terminal
curl -X POST -H "Authorization: Bearer $QG_TOKEN" -H "Content-Type: application/json" \
  "https://qualitygraph.harnessqa.dev/api/tms/releases" \
  -d '{"orgId":"YOUR_ORG_ID","name":"2026.10","version":"v2026.10.0","notes":"## Checklist\n- [ ] smoke test"}'

Organizations

Organizations are the top-level scope for all resources. Your API token is bound to one organization.

GET
/organizations

List organizations you belong to

GET
/organizations/:id

Get organization details

GET
/organizations/:id/dashboard

Dashboard summary with KPIs

GET
/organizations/:id/repositories

List repositories

GET
/organizations/:id/coverage-matrix

Coverage matrix across repos

GET
/organizations/:id/analytics

Organization-level analytics

Get your organization ID

terminal
curl -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/organizations"

Members & Invitations

Roles are owner, admin and member. Owners and admins manage members; only owners hand out the owner role. An organization always keeps at least one owner.

GET
/organizations/:id/members

Members with roles, plus your own permissions and whether email delivery is configured

PATCH
/organizations/:id/members/:userId

Change a role: { role }

DELETE
/organizations/:id/members/:userId

Remove a member (or leave, when it is you)

POST
/organizations/:id/members/:userId/password-reset

Email that member a password reset link

GET
/organizations/:id/invitations

Pending invitations

POST
/organizations/:id/invitations

Invite by email: { email, role } → invitation, inviteUrl, emailSent

POST
/organizations/:id/invitations/:invitationId/resend

Send a fresh link (the previous one is superseded)

DELETE
/organizations/:id/invitations/:invitationId

Revoke an invitation

GET
/invitations/:token

Public: what an invite link points to and its status

POST
/invitations/:token/accept

Accept as the signed-in user

Repositories

GET
/repositories?orgId=:orgId

List repositories

GET
/repositories/:id

Repository details: branches, latest coverage per layer, latest health score, and stats (PR counts with high-risk open ones, commits, last commit, last coverage, test runs, last run)

GET
/repositories/:id/health

Health score and components

GET
/repositories/:id/coverage

Latest coverage per test layer; provider tells whether it was measured (LCOV, COBERTURA, JACOCO, CODECOV) or estimated from the file layout (MANUAL). A measurement always outranks an estimate

GET
/repositories/:id/coverage/by-type

Coverage broken down by test type, with the ten least-covered files of each latest run

POST
/repositories/:id/coverage/upload

Upload a coverage report: { format: lcov | cobertura | jacoco, data: '<file contents>', testType?, branch?, commitSha?, pathPrefix?, flags? }. Stored with per-file and per-line detail

POST
/cli/coverage

Same upload, addressed by repository name: { repoName, fullName, ...report } — what qg analyze and qg coverage upload call

GET
/repositories/:id/unique-coverage

Unique coverage contribution per test type

GET
/repositories/:id/coverage/contribution

Unique vs shared lines per test type (computed from file-level data)

GET
/repositories/:id/regressions

Regression alerts for the repository

DELETE
/repositories/:id

Soft-delete a repository

Quality & Analytics

Everything behind the dashboard's health scores, trends, flaky-test and CI-waste panels, and the quality gates.

GET
/organizations/:id/dashboard

KPIs: health, coverage by type, flaky tests, pass rate, CI waste, high-risk PRs

GET
/organizations/:id/health

Organization health score

GET
/organizations/:id/regressions

Repositories whose health dropped, by severity

GET
/organizations/:id/recommendations

Prioritised recommendations

GET
/organizations/:id/trends?period=30d&metrics=score,coverage

Org-level trend series (7d, 30d, 90d, 6m, 1y)

GET
/repositories/:id/trends?period=30d

Repository trend series per component

GET
/repositories/:id/trends/regressions?period=30d

Oldest-vs-newest comparison with warning/critical thresholds

GET
/organizations/:id/flaky-tests?limit=50

Flaky tests across the organization, by impact

GET
/repositories/:id/flaky-tests?limit=50

Flaky tests of one repository

POST
/repositories/:id/flaky-tests/calculate

Recompute flaky metrics from test runs

GET
/organizations/:id/ci-waste?period=30d

CI minutes and cost lost to retries and failures

GET
/organizations/:id/quality-gates

Quality gate thresholds (null when unset)

PUT
/organizations/:id/quality-gates

Set thresholds: changedCodeCoverage.minimum, overallCoverage.maximumDecrease, criticalRisk.blockMerge, contractChanges.requireContractCoverage, flakyTestImpact.maxAllowed

GET
/repositories/:id/quality-gates/evaluate

Evaluate the gates against the latest data

POST
/repositories/:id/health/calculate

Recalculate a repository's health score

Pull Requests

GET
/repositories/:id/pull-requests?page=1&limit=20

Paginated PRs with their latest risk

GET
/organizations/:id/high-risk-prs

Open PRs with risk 60 or more

GET
/pull-requests/:id

PR with files, risk snapshots and findings

GET
/pull-requests/:id/risk

Risk score and factors (computed on first read)

POST
/pull-requests/:id/risk/calculate

Recompute and store a new risk snapshot

POST
/pr-risk/organizations/:id/calculate

Recompute risk for every open PR in the organization

GET
/pull-requests/:id/test-gaps

Findings: missing API/UI/contract coverage, migrations, untested changes

GET
/repositories/:id/test-mappings

Which tests cover which files

GET
/repositories/:id/test-mappings/code/:filePath

Tests covering one file

GET
/repositories/:id/test-mappings/tests/:testFilePath

Files covered by one test

POST
/repositories/:id/test-mappings/build

Rebuild mappings from coverage and naming conventions

Ingest & CLI

Push results from CI. Unparsable payloads answer 400 with the parser's message.

POST
/repositories/:id/test-runs/ingest

{ format: junit | playwright | pact | json, data, commitSha?, branch? }

GET
/repositories/:id/test-runs?page=1&limit=20

Ingested test runs

GET
/repositories/:id/test-runs/:runId

One run with its executions

POST
/cli/analyze

What the qg CLI uploads: { repoName, fullName, analyses: [{ testType, coveragePercent, ... }] }

terminal
curl -X POST -H "Authorization: Bearer $QG_TOKEN" -H "Content-Type: application/json" \
  "https://qualitygraph.harnessqa.dev/api/repositories/YOUR_REPO_ID/test-runs/ingest" \
  -d "{\"format\":\"junit\",\"branch\":\"main\",\"data\":$(jq -Rs . < junit.xml)}"

Reports

Aggregated stats and trends for the TMS module.

GET
/tms/reports/summary?orgId=:orgId

Overall TMS summary (case counts, pass rates)

GET
/tms/reports/runs?orgId=:orgId

Run history with pass-rate trends

Get TMS summary

terminal
curl -H "Authorization: Bearer $QG_TOKEN" \
  "https://qualitygraph.harnessqa.dev/api/tms/reports/summary?orgId=YOUR_ORG_ID"
response
{
  "data": {
    "totalCases": 142,
    "totalRuns": 28,
    "overallPassRate": 87.3,
    "avgDurationMinutes": 12.5,
    "casesByPriority": {"LOW": 20, "MEDIUM": 68, "HIGH": 42, "CRITICAL": 12},
    "casesByStatus": {"ACTIVE": 130, "DRAFT": 8, "DEPRECATED": 4},
    "recentRuns": [...],
    "passRateTrend": [...]
  }
}

OpenAPI

The complete, generated reference with request and response schemas is served by the API itself. Paste your token into the Authorize button to try calls from the browser.

Open Swagger UI

Error Handling

The API uses standard HTTP status codes. Error responses include a descriptive message.

CodeStatusDescription
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestMissing required fields or invalid data
401UnauthorizedMissing, invalid, or expired token
403ForbiddenToken valid but no access to this resource
404Not FoundResource does not exist
500Server ErrorInternal server error

Error response example

401 response
{
  "statusCode": 401,
  "message": "Invalid or expired API token",
  "error": "Unauthorized"
}

Rate Limits

The API does not currently enforce rate limits. Use reasonable request volumes — excessive requests may be throttled in future versions.

Best practices:

  • Use bulk endpoints (POST /tms/cases/bulk) instead of individual creates
  • Cache organization and repository IDs — they don't change frequently
  • Use query parameters to filter server-side rather than fetching all data

QualityGraph API v1 — Programmatic QA intelligence. Get API Token · CLI Docs · Sign in · Pricing