REST API at a glance

The Kaizen platform exposes a Fastify-backed REST API at https://api.kaizenreports.com. All endpoints are JSON, authenticated via bearer token (workspace tokens or short-lived user tokens).

Authorization: Bearer krt_xxx
Content-Type: application/json

Response envelope: bare resource on success, { "error": { "code", "message", "details" } } on failure.

Workspaces & projects

GET /v1/projects

List projects in the caller's workspaces.

curl https://api.kaizenreports.com/v1/projects \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "id": "prj_01h...",
    "slug": "acme-web",
    "name": "Acme Web",
    "workspace": { "id": "ws_01h...", "slug": "acme" },
    "accessMode": "team",
    "stats": { "lastRunAt": "2026-04-30T12:04:00Z", "passRate30d": 0.964, "flakyCount": 4 }
  }
]

GET /v1/projects/:slug

One project with extended stats (history range, top-failing suites, defect counts).

Runs

GET /v1/runs/:id

Fetch a single run including its kensho/v1 payload (compact form):

curl https://api.kaizenreports.com/v1/runs/run_01h... \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "id": "run_01h...",
  "project": { "slug": "acme-web" },
  "externalRunId": "github-actions-7891",
  "branch": "main",
  "commit": "a91c3e2",
  "status": "closed",
  "startedAt": "2026-04-30T12:00:14Z",
  "finishedAt": "2026-04-30T12:04:08Z",
  "totals": { "passed": 824, "failed": 17, "skipped": 13, "broken": 0, "flaky": 4 },
  "casesUrl": "https://api.kaizenreports.com/v1/runs/run_01h.../cases",
  "kenshoReportUrl": "https://reports.kaizenreports.com/run_01h.../"
}

GET /v1/runs/:id/cases

Paginated case_runs (1k per page, ?cursor= for next).

GET /v1/runs/:id/cases/:caseId

Single case run with full step tree, attachments, history.

Ingest — push a Kensho report

Two-phase upload. The kensho push CLI uses these endpoints; you can also call them directly.

POST /v1/ingest/kensho/init

Describe attachments. Server returns presigned PUT URLs (5-min TTL) and a list of attachments already on S3 (deduped by sha256). Upload state cached in Redis under ingest:upload:<uploadId> for 30 min.

// request
{
  "workspaceSlug": "acme",
  "projectSlug": "acme-web",
  "externalRunId": "github-actions-7891",
  "attachments": [
    { "id": "att_01h...", "sha256": "ab12...", "size": 102400, "contentType": "image/png" }
  ]
}
// response
{
  "uploadId": "upl_01h...",
  "expiresAt": "2026-04-30T12:34:08Z",
  "presigned": [
    { "id": "att_01h...", "url": "https://s3.../...", "fields": { /* ... */ } }
  ],
  "alreadyExists": []
}

POST /v1/ingest/kensho/finalize

Submit run.json + cases. Server validates against kensho/v1 schema, persists, computes regression vs previous run on the same branch, enqueues post-ingest job, returns summary.

// request body — same schema as kensho-results/run.json
{
  "uploadId": "upl_01h...",
  "schemaVersion": "kensho/v1",
  "runId": "...",
  "project": { "slug": "acme-web" },
  "env": { /* ... */ },
  "totals": { /* ... */ },
  "cases": [ /* ... */ ]
}

Idempotent on (workspace, project, externalRunId) — re-pushing the same run returns the existing internalRunId.

// response
{
  "internalRunId": "run_01h...",
  "kenshoReportUrl": "https://reports.kaizenreports.com/run_01h.../",
  "regression": {
    "newFailures": 3,
    "fixed": 1,
    "stillFailing": 14
  }
}

Test cases

  • GET /v1/projects/:slug/cases — paginated case inventory
  • GET /v1/cases/:id — single case with rolled-up history
  • PATCH /v1/cases/:id — update labels, owner, defect links

Test plans & executions

  • GET /v1/projects/:slug/plans
  • POST /v1/projects/:slug/plans — create
  • POST /v1/plans/:id/executions — start an execution
  • PATCH /v1/executions/:id/cases/:caseId — set verdict (manual mode)

Defects & analytics

  • GET /v1/projects/:slug/defects
  • GET /v1/projects/:slug/analytics?metric=passrate&window=30d
  • GET /v1/projects/:slug/flaky

Rate limits

  • Anonymous — none allowed; everything requires auth
  • User token — 600 requests/min
  • Workspace token — 6,000 requests/min
  • Ingest endpoints — 60 finalize/min/project; init has no per-call limit

Bursts are smoothed via a token bucket. 429 responses include Retry-After.

Webhooks (preview)

POST /v1/projects/:slug/webhooks — register a URL, choose events (run.finalized, defect.opened, flaky.detected). HMAC-signed with your project's signing secret. See Defects & flaky for the most common consumer pattern.

OpenAPI spec

Live at https://api.kaizenreports.com/v1/openapi.json. Generates SDKs via openapi-generator.