API ReferenceCI/CD Results Upload

CI/CD Results Upload

Push automated test results from your CI/CD pipeline into a Testably run. Supports JSON and JUnit XML formats. This endpoint is called automatically by the @testably.kr/playwright-reporter, @testably.kr/cypress-reporter, and @testably.kr/jest-reporter SDKs.

Base URL:https://api.testably.app/v1

SDK handles this automatically

In most cases you do not need to call this endpoint directly. Install one of the reporter SDKs and configure your TESTABLY_TOKEN and TESTABLY_RUN_ID environment variables — the SDK will call this endpoint after your test suite finishes. Direct calls are for advanced use cases.

View SDK setup guide
POST/v1/results

Upload one or more test results into an existing run. Results are matched by test_case_id. Each upload is idempotent — re-uploading the same test_case_id overwrites the previous result.

Authentication

Authorization: Bearer <CI_TOKEN>

Use a project-scoped CI token from Settings → API Tokens. The token must have write access to the target project.

Request Body Parameters

NameTypeRequiredDescription
run_idstringRequiredThe test run ID to upload results into
resultsarrayOptionalArray of result objects (JSON format). Required if junit_xml is not provided.
results[].test_case_idstringRequiredTest case ID to match within the run
results[].statusstringRequiredResult status: passed, failed, blocked, retest, not_tested
results[].notestringOptionalOptional note or error message from the test
results[].elapsedintegerOptionalTime spent in seconds
formatstringOptionalInput format: "json" (default) or "junit"
junit_xmlstringOptionalRaw JUnit XML string. Required if format is "junit".
dry_runbooleanOptionalIf true, validates the payload without persisting results. Defaults to false.

Example — JSON Format

{
  "run_id": "run_abc123",
  "format": "json",
  "results": [
    {
      "test_case_id": "tc_001",
      "status": "passed",
      "elapsed": 12
    },
    {
      "test_case_id": "tc_002",
      "status": "failed",
      "note": "AssertionError: expected 200 but got 500",
      "elapsed": 8
    },
    {
      "test_case_id": "tc_005",
      "status": "blocked",
      "note": "Staging DB unavailable"
    }
  ]
}

Example — JUnit XML Format

{
  "run_id": "run_abc123",
  "format": "junit",
  "junit_xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n  <testsuite name=\"Login Tests\" tests=\"3\">\n    <testcase name=\"login with valid credentials\" time=\"0.012\" />\n    <testcase name=\"login with invalid password\" time=\"0.008\">\n      <failure>AssertionError: expected 200 but got 500</failure>\n    </testcase>\n  </testsuite>\n</testsuites>"
}

Response — 200 Success

{
  "success": true,
  "uploaded_count": 3,
  "failed_count": 0,
  "stats": {
    "passed": 2,
    "failed": 1,
    "blocked": 0,
    "retest": 0,
    "not_tested": 0
  }
}

Response — 207 Partial Failure

{
  "success": false,
  "partial_failure": true,
  "uploaded_count": 2,
  "failed_count": 1,
  "stats": {
    "passed": 1,
    "failed": 1,
    "blocked": 0,
    "retest": 0,
    "not_tested": 0
  },
  "errors": [
    {
      "test_case_id": "tc_999",
      "error": "test_case_id not found in this run"
    }
  ]
}

Rate Limiting

Limit

60

requests per minute per token

Payload Size

10 MB

max request body size

On Limit Exceeded

429

check Retry-After header

Error Codes

StatusMeaningDescription
200OKAll results uploaded successfully.
207Multi-StatusPartial success. Some results uploaded; see failed_count and errors array.
400Bad RequestInvalid payload structure, missing required fields, or unknown status value.
401UnauthorizedMissing or invalid Authorization header.
403ForbiddenToken does not have write access to this project.
404Not Foundrun_id does not exist or does not belong to the authenticated project.
429Too Many RequestsRate limit exceeded. Retry after the time specified in Retry-After header.
500Internal Server ErrorUnexpected server error. Contact support if this persists.

Using the SDKs (Recommended)

Rather than calling this endpoint directly, use one of the reporter SDKs. They handle authentication, run creation, and result upload automatically.

Playwright@testably.kr/playwright-reporter
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['@testably.kr/playwright-reporter', {
      token: process.env.TESTABLY_TOKEN,
      runId: process.env.TESTABLY_RUN_ID,
    }]
  ],
});
Jest@testably.kr/jest-reporter
// jest.config.ts
export default {
  reporters: [
    'default',
    ['@testably.kr/jest-reporter', {
      token: process.env.TESTABLY_TOKEN,
      runId: process.env.TESTABLY_RUN_ID,
    }]
  ],
};

Product

Use Cases

Compare

Resources

Legal

© 2026 Testably. All rights reserved.

We use cookies to improve your experience.

Strictly necessary cookies are required for login and security. Optional cookies help us analyze usage and improve our service. Learn more →