Skip to main content

Reference: POST /runs/ingest

Endpoint for recording the results of a run in Qably as JSON: authentication, examples, fields, and responses.

Ingests execution results for a test suite. Authenticate using Authorization: Bearer <project API key>. The target project and organization are resolved directly from the key.

Example request

curl --fail --silent \
  --request POST \
  "https://api.qably.dev/runs/ingest" \
  --header "Authorization: Bearer $QABLY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "externalId": "gh-run-482913",
    "source": "github_actions",
    "suiteId": "suite_123",
    "name": "Checkout regression - main",
    "startedAt": "2026-09-01T10:00:00Z",
    "finishedAt": "2026-09-01T10:04:12Z",
    "commitSha": "a1b2c3d",
    "commitMessage": "fix: checkout rounding",
    "commitAuthor": "Ada Lovelace",
    "cases": [
      { "name": "Adds an item to the cart", "status": "pass" },
      {
        "name": "Applies a discount code",
        "steps": ["open cart", "apply code SAVE10"],
        "expectedResult": "total is reduced by 10%",
        "status": "fail"
      }
    ]
  }'

Request fields

FieldRequiredNotes
externalIdyesNon-empty string. Idempotency key used to update existing records instead of creating duplicates.
sourceno"api" (default) or "github_actions".
suiteId / suiteNameexactly oneAn unresolvable suiteId returns 404. An unresolvable suiteName registers the suite automatically.
nameyesDisplay name for the test run, up to 200 characters.
startedAt / finishedAtnoISO 8601 timestamps with explicit time zone offset.
commitSha / commitMessage / commitAuthornoOptional commit metadata, up to 64, 2000, and 200 characters respectively.
casesyesArray containing at least one test case.

Case fields

Case fieldRequiredNotes
nameyesUp to 372 characters.
suiteNamenoDefaults to the resolved suite name; allows attaching auxiliary labels (such as Playwright project names) for audit trails.
stepsnoArray of strings, up to 50 items (500 characters max each). Empty by default on JUnit imports; can be populated when posting JSON directly.
expectedResultnoUp to 1000 characters. Empty by default on JUnit imports.
statusyesOne of pending, running, pass, fail, skip, blocked.
recordedAtnoISO 8601 timestamp with explicit time zone offset.

Run status

Run status is determined on the server and does not trust client-calculated summaries. A single failing case marks the entire run as failed. Unresolved pending or running cases maintain the run in an executing state. A run passes only when at least one case passes or is skipped with no accompanying failures. Runs where all cases are blocked count as failed because no verifications took place.

Replays and idempotency

Submitting matching (project, source, externalId) tuples updates the existing run instead of duplicating records. The case list is replaced entirely, and optional metadata fields are updated when provided in subsequent payloads. The API responds with 200 OK on both initial creation and replays.