On this page
API & Automation
Proba.run exposes a machine-facing layer for CI pipelines and scripts: a public REST API for reading and writing your test data, dedicated endpoints for submitting automated test results, and one-way synchronization of test cases with a git repository. All of it is authenticated with an API key instead of a user session.
API keys
An API key is a project-scoped secret used for machine access — no login, no 2FA. Create one from your project settings, on the API keys tab.
- Click New key and give it a name.
- The raw key is shown exactly once, right after creation. Copy it immediately — Proba.run only stores a hash, so it cannot be shown again.
- Send the key on every request in the
X-Api-Keyheader.
Each key has a scope:
| Scope | Can do |
|---|---|
full (default) | Read and write everything the key's owner can access in the project |
read_only | Read endpoints only — any write request returns an error |
Use a read_only key wherever a script or integration only needs to read data (for example, the case sync skill described below). Revoke a key from the same tab at any time; revoked keys stop working immediately.
Public REST API
The public API lives under /api/v1/** and is scoped to the project the key belongs to — there is no project identifier in the URL, so a key can never reach another project's data.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/project | Project metadata |
| GET | /api/v1/cases | List cases (filter by folder, priority, status, search, archived) |
| GET | /api/v1/cases/{caseNumber} | Case detail with fully expanded steps |
| POST | /api/v1/cases | Create a case |
| PATCH | /api/v1/cases/{caseNumber} | Update a case (partial) |
| DELETE | /api/v1/cases/{caseNumber} | Move a case to the project trash |
| POST | /api/v1/cases/import | Bulk-import cases (folders and tags resolved by name) |
| GET | /api/v1/tags | Project tags (source of tagIds for case writes) |
| GET | /api/v1/folders | Project folders |
| GET | /api/v1/runs | List runs |
| GET | /api/v1/runs/{runNumber} | Run detail with progress |
| GET | /api/v1/runs/{runNumber}/cases | Run cases, paginated |
| POST | /api/v1/runs | Create a run |
| PATCH | /api/v1/runs/{runNumber} | Update a run (name, description, close/reopen) |
| POST | /api/v1/runs/{runNumber}/cases/{caseNumber}/results | Submit a result |
| GET | /api/v1/tasks | Tasks with their requirements |
| GET | /api/v1/sync/manifest | Full case manifest for git sync (see below) |
List endpoints are paginated with ?page and ?perPage (default 25, maximum 100) and return { items, total, page, perPage, totalPages }. Any error responds with { "error": "...", "code": "..." } — branch your client logic on code (unauthorized, not_found, validation_failed, archived, rate_limited), not on the error text.
Example requests
List a project's active cases:
curl -H "X-Api-Key: qalab_xxx" \
"https://your-instance.example.com/api/v1/cases?status=active&page=1"
Submit a result for a case in an existing run:
curl -X POST \
-H "X-Api-Key: qalab_xxx" \
-H "Content-Type: application/json" \
-d '{"status":"passed","elapsedSeconds":1.4}' \
"https://your-instance.example.com/api/v1/runs/42/cases/DMO-17/results"
Creating and editing cases via the API
POST /api/v1/cases creates a single case and responds with the same shape as the case detail endpoint. title is required; optional fields are folderId (must belong to the project), priority (low|medium|high|critical), status (active|draft|deprecated), description, preconditions, tagIds (uuids from GET /api/v1/tags), and steps in one of two forms — a steps array of { "step", "expected" } objects, or a plain-text stepsText (optionally with expectedText). Passing both forms at once is rejected.
PATCH /api/v1/cases/{caseNumber} updates only the fields you send (an empty patch is rejected): same fields as create, plus folderId: null moves the case to the project root and tagIds replaces the whole tag set. DELETE /api/v1/cases/{caseNumber} soft-deletes the case into the project trash — restoring or purging stays in the UI.
curl -X POST \
-H "X-Api-Key: qalab_xxx" \
-H "Content-Type: application/json" \
-d '{"title":"Login works","priority":"high","steps":[{"step":"Open /login","expected":"Form is shown"}]}' \
"https://your-instance.example.com/api/v1/cases"
POST /api/v1/cases/import accepts { "cases": [...] } with up to 2000 items and follows the CSV import semantics: folders and tags are resolved by name (created when missing), steps are plain text only (stepsText), and an unknown priority/status silently falls back to the default (medium/active). Invalid items do not fail the batch — the response is { "imported": N, "errors": [{ "row": 3, "reason": "..." }] } with 1-based row numbers. Item fields: title (required), folder, priority, status, description, preconditions, tags (array of names), stepsText.
curl -X POST \
-H "X-Api-Key: qalab_xxx" \
-H "Content-Type: application/json" \
-d '{"cases":[{"title":"Login works","folder":"Auth","tags":["smoke"],"stepsText":"1. Open /login"}]}' \
"https://your-instance.example.com/api/v1/cases/import"
Both endpoints require a full-scope key. Bulk import is additionally covered by the import rate limit and is only available on plans that include imports.
Submitting automated test results
For CI pipelines that just need to report results without managing runs case by case, use the automation endpoints. Both create a closed run in one call and auto-create any missing test case by title.
POST /api/automation/runs— JSON body with a runnameand aresultsarray (title,status, optionalelapsedSeconds/comment).POST /api/automation/runs/junit— multipart upload of a JUnit XML file plus anamefield.
Both require X-Api-Key and return the created run, including its progress summary, so CI can link back to it.
Rate limits
Every machine endpoint is rate-limited per API key, with a 429 response and a Retry-After header when exceeded:
| Endpoints | Limit |
|---|---|
Public API (/api/v1/**) | 120 requests / minute |
| Automation result submission | 30 requests / minute |
Syncing test cases with a git repository
Instance owners can link a project to a GitHub repository so test cases stored as markdown files stay in sync with Proba.run. This is aimed at teams that want Claude Code (or another tool working inside the repo) to read, review, and test against the same case files the team edits in Proba.run.
- Repository to Proba.run: from the project's Repository sync settings, configure the repo (owner, name, branch, path prefix) and a token, then click Synchronize. A preview shows what will be created, updated, moved, or unlinked before anything is written.
- Proba.run to repository: the
/api/v1/sync/manifestendpoint returns the current state of every synced case as file content. A companion skill, installed into the repository, pulls this manifest and updates local files to match — creating, overwriting, moving, or removing files as needed. It never commits or pushes; that stays a manual, reviewed step.
A read_only API key is the recommended choice for the sync skill, since it only ever needs to read the manifest.