Ingest (CI/CD)
The ingest endpoint is the primary integration point for CI/CD pipelines. It creates a test run and populates all results in a single request — no separate "create run" + "add results" calls needed.
Endpoint
POST /api/v1/ingest
Authorization: Bearer qh_... (write scope required)
Content-Type: application/json
Request body
{
"project_id": "clxyz123",
"run_name": "CI build #442 — main branch",
"environment": "staging",
"framework": "playwright",
"results": [
{
"test_case_code": "TC-001",
"status": "PASSED",
"duration_ms": 1240
},
{
"test_case_code": "TC-002",
"status": "FAILED",
"error_message": "Assertion failed: expected 200 but got 500",
"error_stack": "Error: ...",
"duration_ms": 3800
},
{
"title": "Should load the homepage in < 2s",
"status": "PASSED",
"duration_ms": 890
}
]
}
Top-level fields
| Field | Required | Description |
|---|---|---|
project_id | Yes | Project UUID to create the run under |
run_name | No | Display name; defaults to timestamp if omitted |
environment | No | Environment label (e.g., staging) |
framework | No | Default framework for all results (overridable per result) |
results | Yes | Array of result objects |
Result fields
Results reference existing test cases by test_case_code or test_case_id. If neither is provided, a new NativeTestResult is recorded as an unlinked result (tracked in metrics but not linked to a library test case).
Mapping tests to the library with @qa-hub tags
Tag your automated tests with a QA Hub code in the title using @qa-hub('TC-001'):
// Playwright
test("Login — invalid password @qa-hub('TC-042')", async ({ page }) => {
// ...
});
// Jest
it("should reject expired tokens @qa-hub('TC-017')", () => {
// ...
});
When the CLI parses the result file, it extracts the tag and sets test_case_code automatically before posting to /api/v1/ingest.
Response codes
| Code | Meaning |
|---|---|
201 | All results accepted, run created |
207 | Partial — some results rejected. Check errors[] in the body. |
207 partial response
{
"run_id": "clrun999",
"accepted": 14,
"rejected": 2,
"errors": [
{ "index": 3, "error": "test_case_code TC-999 not found in this tenant" },
{ "index": 7, "error": "invalid status value: 'pass' (use PASSED)" }
]
}
Using with the CLI
The @qa-hub/cli parses your test framework's output format and calls this endpoint automatically:
qa-hub upload \
--token qh_abc_secret \
--url https://your-qahub.com \
--project clxyz123 \
--format playwright \
--run-name "CI #442" \
playwright-results.json
Data retention
Ingested NativeTestResult rows are retained for a configurable number of days (default: 30). Trigger a sweep via:
curl -X POST https://your-qahub.com/api/v1/admin/sweep \
-H "Authorization: Bearer qh_..."