Skip to content

Milestones API

Milestones are project-scoped planning units that group test runs and track release progress. Each milestone has a server-assigned ULID, a status lifecycle (upcomingactivecompleted | archived), optional date fields, and an optional parent for 1-level hierarchies.

POST/api/v1/projects/{projectId}/milestones

{projectId} is the project code (for example ACME).

FieldRequiredNotes
nameyesNon-empty string, max 255 characters. Must be unique among live milestones in the project
descriptionnoFree-text description, max 2000 characters
statusnoOne of upcoming, active, completed, archived. Defaults to upcoming
startAtnoUnix epoch milliseconds. Must be ≤ dueAt when both are provided
dueAtnoUnix epoch milliseconds
forecastAtnoUnix epoch milliseconds
parentIdnoULID of the parent milestone in the same project (1 level only)

Client-supplied ulid fields are rejected.

Duplicate live name within the project returns 409 conflict. Date ordering violation (dueAt < startAt) or missing required fields return 422 validation_failed.

201 with the created milestone object. See Response fields.

Terminal window
curl -sS -X POST \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"v2.0 Release","status":"upcoming","startAt":1700000000000,"dueAt":1700600000000}' \
"https://probara.net/api/v1/projects/ACME/milestones"
GET/api/v1/projects/{projectId}/milestones

Returns the live (non-deleted) milestones for the project, ordered by ULID ascending. Page-based pagination.

ParameterNotes
pagePage number (1-based, default 1)
pageSizeItems per page (default 50, max 200)
qCase-insensitive substring search on milestone name
statusFilter by exact status: upcoming, active, completed, or archived
viewResponse shape: flat (default) or tree. See List views

The view parameter selects the response shape. It is additive — omitting it (or passing flat) returns the exact same response as before.

viewitemstotalPagination unit
flat (default)Every live milestone (parents and children as siblings)Count of all live milestonesIndividual milestone
treeParent milestones only (those with no parent), each carrying a children array of its live direct childrenCount of parent milestones only (children are never counted)Parent milestone

In tree mode:

  • items contains only parents. Each parent item is the standard milestone object plus a children array.
  • Each entry in children is a plain milestone object (the same response shape); children never carry their own children key (the hierarchy is one level).
  • q and status filter parents only. A parent matched by the filter shows all of its live children regardless of the children’s own status.
  • total is the parent count, so the pager (X–Y of Z) counts parent sections. A parent and its children are never split across pages.
  • A parent with no children has children: [].

200 with { items, page, pageSize, total }. In flat mode each item follows the response shape; in tree mode each item is that shape extended with a children array (see List views).

Terminal window
# Flat (default)
curl -sS \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
"https://probara.net/api/v1/projects/ACME/milestones?status=active"
# Grouped parent sections with nested children
curl -sS \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
"https://probara.net/api/v1/projects/ACME/milestones?view=tree"

Example tree response (truncated):

{
"items": [
{
"ulid": "01JPARENT...",
"name": "v2.4 Release",
"status": "active",
"children": [{ "ulid": "01JCHILD...", "name": "Auth 2.4", "status": "active" }]
}
],
"page": 1,
"pageSize": 50,
"total": 1
}
GET/api/v1/milestones/{milestoneUlid}

Returns a single live milestone scoped to the active organization, including real-time progress aggregates.

Returns 404 not_found when the milestone is outside the active organization or has been deleted.

Terminal window
curl -sS \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
"https://probara.net/api/v1/milestones/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
PATCH/api/v1/milestones/{milestoneUlid}

Partial update. At least one field must be provided; an empty body returns 422 validation_failed.

FieldRequiredNotes
namenoNon-empty string, max 255 characters
descriptionnoMax 2000 characters, or null to clear
statusnoTarget status. Must follow valid status transitions (see Status lifecycle)
startAtnoUnix epoch milliseconds, or null to clear
dueAtnoUnix epoch milliseconds. Must be ≥ startAt when both are set
forecastAtnoUnix epoch milliseconds, or null to clear
parentIdnoULID of the new parent in the same project, or null to detach

Invalid status transitions return 422 validation_failed. Duplicate live name returns 409 conflict. Returns 404 not_found when the milestone is outside the active organization.

Terminal window
curl -sS -X PATCH \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status":"active","dueAt":1700700000000}' \
"https://probara.net/api/v1/milestones/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
DELETE/api/v1/milestones/{milestoneUlid}

Soft-deletes the milestone. Returns 204 on success. Subsequent GET returns 404 not_found and the milestone is excluded from list results.

Deletion atomically unassigns all linked test runs, test cases, and child milestones.

Returns 404 not_found when the milestone is outside the active organization.

Terminal window
curl -sS -X DELETE \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
"https://probara.net/api/v1/milestones/01JXXXXXXXXXXXXXXXXXXXXXXXXX"

Milestones follow a directed state machine. Only the transitions listed below are accepted; all others return 422 validation_failed.

FromAllowed transitions
upcomingactive, archived
activecompleted, archived
completedactive (reopen), archived
archived— (terminal)

Transitioning to completed automatically sets completedAt to the current timestamp. Transitioning away from completed clears completedAt.

All mutating endpoints (POST, PATCH) and GET /api/v1/milestones/{milestoneUlid} return a single milestone object.

FieldTypeNotes
ulidstring (ULID)Server-assigned unique identifier
projectIdstringThe project code this milestone belongs to
namestringDisplay name
descriptionstring | nullOptional description
statusstringCurrent status: upcoming, active, completed, or archived
startAtnumber | nullUnix epoch milliseconds
dueAtnumber | nullUnix epoch milliseconds
forecastAtnumber | nullUnix epoch milliseconds
completedAtnumber | nullSet automatically when status transitions to completed
parentIdstring (ULID) | nullParent milestone ULID, or null for top-level
progress.totalRunsnumberTotal test runs linked to this milestone
progress.closedRunsnumberClosed (finished) test runs
progress.percentCompletenumberclosedRuns / totalRuns × 100, rounded; 0 when no runs
progress.passRatenumberpassed / totalResults × 100, rounded; 0 when no results
progress.passednumberTest case results that passed across all linked runs
progress.failednumberTest case results that failed
progress.blockednumberTest case results that were blocked
progress.skippednumberTest case results that were skipped
progress.untestednumberTest cases not yet executed
authorobject | nullUser who created the milestone, or null for API-token-created and legacy milestones
author.kindstringAlways "user" when present
author.ulidstring (ULID)User identifier
author.displayNamestringFull name or email of the author
author.avatarKeystring | nullStorage key for the author’s avatar image
childCountnumberNumber of direct child milestones
testCaseCountnumberNumber of test cases linked to this milestone
createdAtnumberUnix epoch milliseconds
updatedAtnumberUnix epoch milliseconds

Milestone mutations emit the following events on the organization activity feed:

ActionTrigger
milestone.createdMilestone created
milestone.updatedAny field updated via PATCH
milestone.status_changedStatus field changed via PATCH
milestone.deletedMilestone soft-deleted

See Audit events.