Ingest API v2 reference
Generated from the same OpenAPI document the ingest service serves at /api/ingest/v2/openapi.json (version 2.0.0). Authentication: X-API-Key header on every request (the liveness probes below are the exception).
GET /healthz
Liveness probe - Health check served directly by the ingest service: self-hosted deployments, local development, direct ingest URLs, and the conformance mock. The official Playwright JS reporter currently probes this path before streaming, with a 2 second timeout, and disables itself for the run if it is unreachable. NOTE: on the m00nreport.com cloud apex this path is currently handled by the frontend edge - only specific path prefixes (such as /api/*) reach the backend there, and /healthz is not among them - use /api/ingest/health when probing through that edge instead. No authentication. Any server implementing this contract should serve BOTH health paths.
{
"ok": true,
"service": "ingest"
}Responses: 200 (Service is alive)
GET /api/ingest/health
Liveness probe (cloud-routable) - Same liveness semantics as /healthz, but routable through edges/proxies where only specific path prefixes (such as /api/*) reach the backend - including the m00nreport.com cloud, where /healthz is not among the reachable prefixes. Prefer this path when probing through such an edge. No authentication.
{
"ok": true,
"service": "ingest"
}Responses: 200 (Service is alive)
POST /api/ingest/v2/run/start
Start a run - Creates a run. The project is derived from the API key. Returns the server-generated runId used by all subsequent calls.
| Field | Type | Required | Description |
|---|---|---|---|
launch | string | yes | Launch (run) title shown in the UI. |
tags | array | no | Labels shown on the launch, usable as dashboard filters. |
total | number | no | Expected total number of tests, if known upfront. |
startedAt | string | no | ISO 8601 timestamp. |
attributes | object | no | Optional key-value metadata shown on the run (e.g. environment, branch). Accepted but not schema-enforced at runtime. |
metadata | object | no | Optional structured metadata (CI context etc). Accepted but not schema-enforced at runtime. |
{
"launch": "Nightly regression",
"tags": [
"smoke"
],
"total": 42,
"startedAt": "2026-07-17T21:00:00.000Z"
}Responses: 200 (Success), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 500 (Unexpected server error)
POST /api/ingest/v2/test/start
Register a test attempt (fire-and-forget) - Registers a client-generated testId so steps can stream before the test finishes. Safe to send without awaiting the response.
| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID returned by run/start. |
testId | string | yes | Client-generated UUID identifying this test attempt group. |
titlePath | array | yes | Path from file/module to test title, e.g. ['auth.spec.ts', 'Login', 'valid credentials'] - the last element is the display title, earlier elements group the test into suites, and a file-like first element becomes the FILE badge (a trailing [chromium]/[firefox]/[webkit] segment renders a browser badge). Reused unchanged across retries. See the guide's "Naming tests: titlePath" section for full semantics and per-ecosystem examples. |
filePath | string | no | Optional source file path, shown alongside the test. Independent of titlePath; not required for the FILE badge, which is derived from titlePath[0]. |
retry | number | no | Zero-based retry attempt index. |
startedAt | string | no | ISO 8601 timestamp. |
{
"runId": "3f0f1e6a-7b1c-4b6e-9a52-1c2d3e4f5a6b",
"testId": "9a1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"titlePath": [
"auth.spec.ts",
"Login",
"valid credentials"
],
"filePath": "tests/auth.spec.ts",
"retry": 0,
"startedAt": "2026-07-17T21:00:01.000Z"
}Responses: 200 (Success), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 500 (Unexpected server error)
POST /api/ingest/v2/test/complete
Complete a test attempt
| Field | Type | Required | Description |
|---|---|---|---|
testId | string | yes | Same client-generated UUID sent to test/start for this attempt. |
runId | string | yes | Run UUID returned by run/start. |
titlePath | array | no | Path from file/module to test title, e.g. ['auth.spec.ts', 'Login', 'valid credentials'] - the last element is the display title, earlier elements group the test into suites, and a file-like first element becomes the FILE badge (a trailing [chromium]/[firefox]/[webkit] segment renders a browser badge). Reused unchanged across retries. See the guide's "Naming tests: titlePath" section for full semantics and per-ecosystem examples. |
filePath | string | no | Optional source file path, shown alongside the test. Independent of titlePath; not required for the FILE badge, which is derived from titlePath[0]. |
annotations | object | no | Free-form key-value metadata for this attempt (e.g. a caseId annotation for test case linking). |
retry | number | no | Zero-based retry attempt index; must match the value sent to test/start. |
startedAt | string | no | ISO 8601 timestamp. |
endedAt | string | no | ISO 8601 timestamp. |
status | passed | failed | skipped | timedOut | timedout | interrupted | yes | Final outcome of this attempt. |
duration | number | no | Milliseconds. Computed from startedAt/endedAt if omitted. |
error | object | no | Failure details (message, stack, etc). Required in practice when status is failed/timedOut. |
steps | array of EmbeddedStep | no | Steps not already sent via steps/stream, in EmbeddedStep shape. |
attachments | array of EmbeddedAttachment | no | Inline base64 attachments in EmbeddedAttachment shape; empty when files were uploaded separately via attachment/upload, attachment/stream, or presign+confirm. |
{
"runId": "3f0f1e6a-7b1c-4b6e-9a52-1c2d3e4f5a6b",
"testId": "9a1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"titlePath": [
"auth.spec.ts",
"Login",
"valid credentials"
],
"status": "passed",
"retry": 0,
"duration": 4210,
"startedAt": "2026-07-17T21:00:01.000Z",
"endedAt": "2026-07-17T21:00:05.210Z",
"steps": [],
"attachments": []
}Responses: 200 (Success), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 500 (Unexpected server error)
POST /api/ingest/v2/steps/stream
Stream live step events (batched) - Batch of step events, possibly spanning multiple tests and runs. Every unique runId in the batch is ownership-checked.
| Field | Type | Required | Description |
|---|---|---|---|
items | array of StepItem | yes | Batch of StepItem events, up to 1000 per call. May span multiple tests and runs. |
{
"items": [
{
"runId": "3f0f1e6a-7b1c-4b6e-9a52-1c2d3e4f5a6b",
"testId": "9a1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"title": "page.click(#login)",
"action": "end",
"status": "passed",
"duration": 120,
"nestingLevel": 0,
"stepIndex": 3
}
]
}Responses: 200 (Success), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 500 (Unexpected server error)
POST /api/ingest/v2/run/end
End a run
| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID returned by run/start. |
status | passed | failed | timedOut | timedout | interrupted | finished | completed | no | Final outcome of the run as a whole. |
endedAt | string | no | ISO 8601 timestamp. |
{
"runId": "3f0f1e6a-7b1c-4b6e-9a52-1c2d3e4f5a6b",
"status": "finished",
"endedAt": "2026-07-17T21:05:00.000Z"
}Responses: 200 (Success), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 500 (Unexpected server error)
POST /api/ingest/v2/attachment/upload
Upload attachments (buffered multipart) - For small files. Multipart form with runId, testId fields and up to 10 file parts.
runId, testId plus up to 10 file parts (200 MB each).| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID returned by run/start. |
testId | string | yes | Client-generated test UUID. |
file | string | yes | One or more file parts. Max 10 files, 200MB each. |
Responses: 200 (Success), 400 (runId and testId are required, or no files provided), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 413 (Per-run attachment byte quota exceeded), 500 (Unexpected server error)
POST /api/ingest/v2/attachment/stream
Upload large attachments (streaming multipart) - For large files (videos, traces). Streams to storage without buffering. Send runId and testId fields BEFORE file parts.
runId, testId plus up to 10 file parts (200 MB each).| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID returned by run/start. |
testId | string | yes | Client-generated test UUID. |
file | string | yes | One or more file parts. Max 10 files, 200MB each. |
Responses: 200 (Success), 400 (runId and testId are required, or no files uploaded), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 413 (Per-run attachment byte quota exceeded), 500 (Unexpected server error)
POST /api/ingest/v2/attachment/presign
Get a presigned direct-upload URL (or check capability) - With {"check": true}: returns whether direct upload is supported. Otherwise returns a presigned PUT URL valid for 10 minutes; upload the file there, then call attachment/confirm.
| Field | Type | Required | Description |
|---|---|---|---|
check | boolean | no | If true, only report capability. |
runId | string | no | Run UUID returned by run/start. |
testId | string | no | Client-generated test UUID. |
filename | string | no | Name of the file to be uploaded. |
contentType | string | no | MIME type of the file to be uploaded. |
size | number | no | File size in bytes; reserved against the run quota at presign time. |
{
"runId": "3f0f1e6a-7b1c-4b6e-9a52-1c2d3e4f5a6b",
"testId": "9a1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"filename": "trace.zip",
"contentType": "application/zip",
"size": 1048576
}Responses: 200 (Success), 400 (Missing required fields: runId, testId, filename, contentType), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 413 (Per-run attachment byte quota exceeded), 500 (Unexpected server error)
POST /api/ingest/v2/attachment/confirm
Confirm a direct upload - Records the attachment after a successful presigned PUT. Quota was already reserved at presign time.
| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID returned by run/start. |
testId | string | yes | Client-generated test UUID. |
attachmentId | string | yes | The attachmentId returned by attachment/presign. |
filename | string | yes | Name of the uploaded file. |
contentType | string | no | MIME type of the uploaded file. |
size | number | no | File size in bytes. |
{
"success": true,
"attachmentId": "7c8d9e0f-1a2b-4c3d-8e5f-6a7b8c9d0e1f",
"objectName": "autotests-attachments/7c8d9e0f-1a2b-4c3d-8e5f-6a7b8c9d0e1f"
}Responses: 200 (Success), 400 (Missing required fields: runId, testId, attachmentId, filename), 401 (Missing or invalid API key), 403 (Run belongs to another organization, or writes are blocked by subscription status), 409 (Run is no longer active (stopped or interrupted)), 500 (Unexpected server error)
Component schemas
Named schemas referenced above by name (e.g. an array of EmbeddedStep field in a table) are defined here.
ErrorEnvelope
| Field | Type | Required | Description |
|---|---|---|---|
error | string | no | Short error category, e.g. Unauthorized, Forbidden, Conflict. |
message | string | no | Human-readable detail; not machine-parseable, use code instead. |
code | API_KEY_REQUIRED | INVALID_API_KEY_FORMAT | INVALID_API_KEY | RUN_ACCESS_DENIED | RUN_NOT_ACTIVE | RUN_ATTACHMENT_LIMIT_EXCEEDED | no | Machine-readable error code. |
RunQuota
Per-run attachment byte quota, by pricing tier.
| Field | Type | Required | Description |
|---|---|---|---|
usedBytes | number | no | Bytes already consumed by this run. |
limitBytes | number | no | Total bytes allowed for this run. |
remainingBytes | number | no | limitBytes minus usedBytes. |
AttachmentResult
One stored attachment, as returned by attachment/upload and attachment/stream.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | no | Attachment UUID. |
name | string | no | Original file name. |
contentType | string | no | MIME type, as provided by the upload. |
size | number | no | File size in bytes. |
StepItem
One step event. Items without runId, testId and title are silently skipped by the server.
| Field | Type | Required | Description |
|---|---|---|---|
runId | string | yes | Run UUID this step belongs to; ownership-checked per batch. |
testId | string | yes | Client-generated test UUID. |
title | string | yes | Step label shown as the row title. |
action | string | no | 'begin' while running, 'end' when finished. Only 'end' (or a final status) is persisted. |
status | string | no | 'running' while in progress, then 'passed' or 'failed'. |
category | string | no | Optional grouping tag, e.g. 'pw:api' for framework-native steps. |
duration | number | no | Milliseconds. |
error | object | no | Failure details for this step, if any. |
nestingLevel | number | no | Zero-based depth for nested steps. |
stepIndex | number | no | Stable per-test index; used to dedupe against test/complete steps. |
EmbeddedStep
One step embedded in test/complete's steps array (distinct from steps/stream's StepItem: no runId/testId per item, since the parent call already carries both for the whole array). No field is required - the server accepts partial items and falls back to array position for ordering when index/stepIndex is omitted.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | no | Step label shown as the row title. |
category | string | no | Optional grouping tag, e.g. 'pw:api' for framework-native steps. |
status | string | no | 'passed', 'failed', 'skipped' or similar. |
duration | number | no | Milliseconds. |
error | object | no | Failure details for this step, if any. |
nestingLevel | number | no | Zero-based depth for nested steps. |
index | number | no | Zero-based step order within this test attempt. This is the field name the official reporter sends; falls back to array position if omitted. |
stepIndex | number | no | Accepted as an alias for 'index' if 'index' is not present. |
EmbeddedAttachment
One inline base64-encoded attachment embedded in test/complete's attachments array (distinct from AttachmentResult, the shape the upload endpoints return). Only sent when the reporter uses binaryAttachments:false; with the default binaryAttachments:true, files are uploaded separately via attachment/upload or attachment/stream and this array is empty. Items without data or name are silently skipped by the server.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | no | Client-generated attachment UUID. Generated server-side if omitted. |
name | string | yes | File name shown on the attachment. |
contentType | string | no | Defaults to 'application/octet-stream' if omitted. |
data | string | yes | Base64-encoded file content. |
compressed | boolean | no | If true, data is gzip-compressed before base64 encoding and is decompressed server-side. |
size | number | no | Informational only: the server recomputes size from the decoded buffer and ignores this value. |