Upload API
Gaffer’s Upload API allows you to upload test reports from any CI/CD system or local environment. The API accepts multipart form data containing your test report files and optional metadata.
Endpoint
Section titled “Endpoint”POST https://app.gaffer.sh/api/upload
Authentication
Section titled “Authentication”All requests must include your project’s upload token in the X-API-Key header.
You can find your upload token in your project settings.
| Header | Description |
|---|---|
X-API-Key | Your project upload token (required) |
Content-Type | multipart/form-data (set automatically by most HTTP clients) |
Request Body
Section titled “Request Body”The request body must be multipart/form-data with the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
files | File(s) | Yes | One or more test report files to upload. Include multiple files by repeating the field. |
tags | JSON string | No | Metadata tags as a JSON object (see below). |
Tags are optional metadata that help you organize and filter your test runs.
Pass them as a JSON string in the tags field.
| Tag | Recommended | Description |
|---|---|---|
commitSha | Strongly recommended | The git commit SHA associated with this test run. |
branch | Recommended | The git branch name (e.g., main, feature/auth). |
test_framework | Optional | The test framework used (e.g., playwright, jest, pytest). |
test_suite | Optional | A label for the test suite (e.g., unit, integration, e2e). |
You can also include any custom tags you like. All tag values must be strings.
File Size Limits
Section titled “File Size Limits”The single-POST endpoint documented here is capped by the Cloudflare edge at 100 MB total per request.
For files larger than 100 MB (Playwright traces, large videos, full HTML reports), use the gaffer CLI or the gaffer-uploader@v2 GitHub Action instead. Both transparently route uploads through Gaffer’s multipart endpoints, supporting individual files up to 5 GB. Your plan’s storage cap is the only practical ceiling.
Supported Report Formats
Section titled “Supported Report Formats”Gaffer supports a variety of test report formats:
- Playwright HTML - Full HTML report with embedded data
- Vitest HTML - Vitest HTML reporter output
- Jest JSON - Native Jest JSON output (
--json) - Jest HTML - jest-html-reporter output
- pytest HTML - pytest-html plugin output
- JUnit XML - Standard JUnit XML format
- Vitest JSON - Vitest JSON reporter output
Example Request
Section titled “Example Request”Single File Upload
Section titled “Single File Upload”curl -X POST https://app.gaffer.sh/api/upload \ -H "X-API-Key: YOUR_UPLOAD_TOKEN" \ -F "files=@playwright-report/index.html" \ -F 'tags={"commitSha":"abc123def456","branch":"main","test_framework":"playwright"}'Multiple Files Upload
Section titled “Multiple Files Upload”curl -X POST https://app.gaffer.sh/api/upload \ -H "X-API-Key: YOUR_UPLOAD_TOKEN" \ -F "files=@playwright-report/index.html" \ -F "files=@playwright-report/data/test-results.json" \ -F 'tags={"commitSha":"abc123","branch":"feature/auth"}'Response
Section titled “Response”A successful upload returns HTTP 201 Created with the following JSON response:
{ "testRun": { "id": "abc123xyz", "uniqueId": "1701234567890", "projectId": "proj_abc123", "commitSha": "abc123def456", "branch": "main", "tags": { "commitSha": "abc123def456", "branch": "main", "test_framework": "playwright" }, "createdAt": "2024-01-15T10:30:00.000Z" }, "files": [ { "filename": "index.html", "size": 245678, "path": "org_123/proj_456/1701234567890/index.html", "contentType": "text/html" } ]}| Field | Description |
|---|---|
testRun.id | Unique identifier for the test run. |
testRun.uniqueId | Timestamp-based identifier. |
testRun.projectId | The project this test run belongs to. |
testRun.commitSha | Git commit SHA (if provided in tags). |
testRun.branch | Git branch name (if provided in tags). |
testRun.tags | All tags provided in the request. |
testRun.createdAt | When the test run was created. |
files | Array of uploaded file details. |
warnings | Optional array of warning messages (e.g., if parsing couldn’t be queued). |
Error Responses
Section titled “Error Responses”| Status | Meaning | Description |
|---|---|---|
400 | Bad Request | No files provided, invalid tags format, or file too large. |
401 | Unauthorized | Missing or invalid upload token. |
402 | Payment Required | Storage limit exceeded. Upgrade your plan for more storage. |
503 | Service Unavailable | Temporary upload failure. Retry the request. |
Next Steps
Section titled “Next Steps”- cURL Guide - Quick examples for uploading with cURL
- GitHub Action - Automate uploads from GitHub Actions