Sprints & Boards
Sprints represent time-boxed iterations within a project. Each sprint moves through a lifecycle: Planned → Active → Completed. The board view groups a sprint’s tickets by status, and the burndown chart tracks daily progress. This guide walks through the full sprint lifecycle.
1. Prerequisites
You need a running Alloy server with a project that has tickets. Set these shell variables for the examples below:
BASE_URL="http://localhost:3000"
Register a user and capture the token:
curl -s -X POST "$BASE_URL/api/v1/auth/register" \
-H "Content-Type: application/json" \
-d '{
"email": "guide-sb@alloy.dev",
"password": "guide-sb-pass1",
"display_name": "SB Guide User"
}' | jq .
{
"user_id": "...",
"email": "guide-sb@alloy.dev",
"display_name": "SB Guide User",
"access_token": "..."
}
Save the token and user ID:
TOKEN="<access_token from above>"
USER_ID="<user_id from above>"
Create an organization and project:
curl -s -X POST "$BASE_URL/api/v1/orgs" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "Sprint Guide Org",
"slug": "guide-sb-org"
}' | jq .
{
"id": "...",
"name": "Sprint Guide Org",
"slug": "guide-sb-org"
}
ORG_ID="<id from above>"
curl -s -X POST "$BASE_URL/api/v1/projects" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"org_id\": \"$ORG_ID\",
\"key\": \"SB\",
\"name\": \"Sprint Board Project\",
\"description\": \"Project for the sprints guide\"
}" | jq .
{
"id": "...",
"org_id": "...",
"key": "SB",
"name": "Sprint Board Project",
"description": "Project for the sprints guide",
"ticket_counter": 0
}
PROJECT_ID="<id from above>"
Create a couple of tickets to work with:
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/tickets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"title\": \"Design landing page\",
\"description\": \"Create the main landing page layout\",
\"priority\": \"High\",
\"reporter_id\": \"$USER_ID\"
}" | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": 1,
"title": "Design landing page",
"description": "Create the main landing page layout",
"status": "Backlog",
"priority": "High",
"reporter_id": "..."
}
TICKET_ID="<id from above>"
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/tickets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"title\": \"Set up database schema\",
\"description\": \"Define initial tables and migrations\",
\"priority\": \"Medium\",
\"reporter_id\": \"$USER_ID\"
}" | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": 2,
"title": "Set up database schema",
"description": "Define initial tables and migrations",
"status": "Backlog",
"priority": "Medium",
"reporter_id": "..."
}
2. Create a Sprint
Sprints belong to a project and require a name, start date, and end date. New sprints start in the Planned status.
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "Sprint 1",
"goal": "Complete MVP foundations",
"start_date": "2026-04-01",
"end_date": "2026-04-15"
}' | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "Complete MVP foundations",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
Save the sprint ID:
SPRINT_ID="<id from above>"
The goal field is optional and describes what the sprint aims to achieve.
CLI shortcut:
alloy sprint create --project "$PROJECT_ID" --name "Sprint 1" --goal "Complete MVP foundations" --start-date 2026-04-01 --end-date 2026-04-15
3. List Sprints
List all sprints in a project:
curl -s "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "Complete MVP foundations",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
],
"next_cursor": null,
"has_more": false
}
Use limit and cursor for pagination when you have many sprints:
curl -s "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints?limit=5" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"name": "Sprint 1",
"status": "Planned"
}
],
"next_cursor": null,
"has_more": false
}
CLI shortcut:
alloy sprint list --project "$PROJECT_ID"
4. Get & Update a Sprint
Fetch a single sprint by ID:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "Complete MVP foundations",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
Update the sprint goal or dates with a PATCH request. Only include the fields you want to change:
curl -s -X PATCH "$BASE_URL/api/v1/sprints/$SPRINT_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"goal": "Ship auth and landing page"}' | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "Ship auth and landing page",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
You can also update the name, start_date, and end_date. Pass null for
the goal field to clear it.
CLI shortcut:
alloy sprint get "$SPRINT_ID" alloy sprint update "$SPRINT_ID" --goal "Ship auth and landing page"
5. Start a Sprint
Transition a sprint from Planned to Active. Only one sprint per project should typically be active at a time.
curl -s -X POST "$BASE_URL/api/v1/sprints/$SPRINT_ID/start" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "...",
"start_date": "...",
"end_date": "...",
"status": "Active",
"created_at": "...",
"updated_at": "..."
}
The status changes to Active. Starting a sprint that is already active or
completed returns an error.
CLI shortcut:
alloy sprint start "$SPRINT_ID"
6. View the Sprint Board
The board endpoint groups a sprint’s tickets by their workflow status, giving you a kanban-style view of the sprint.
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID/board" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint": {
"id": "...",
"project_id": "...",
"name": "...",
"goal": "...",
"start_date": "...",
"end_date": "...",
"status": "...",
"created_at": "...",
"updated_at": "..."
},
"columns": [
{
"status": "...",
"tickets": []
},
{
"status": "...",
"tickets": []
},
{
"status": "...",
"tickets": []
}
]
}
Each column represents a workflow status. Tickets in the sprint appear under their current status column. Move tickets between columns by transitioning their status:
curl -s -X POST "$BASE_URL/api/v1/tickets/$TICKET_ID/transition" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"to_status": "InProgress"}' | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": "...",
"title": "...",
"status": "InProgress",
"priority": "..."
}
CLI shortcut:
alloy ticket transition "$TICKET_ID" --to-status InProgress
7. Track Progress with Burndown
The burndown endpoint returns daily progress data for a sprint, showing how many tickets remain over time:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID/burndown" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint_id": "...",
"data": [
{
"date": "...",
"total_tickets": 0,
"completed_tickets": 0,
"remaining_tickets": 0
}
]
}
Each entry in the data array represents one day and contains:
| Field | Description |
|---|---|
date | The calendar date (ISO 8601) |
total_tickets | Total tickets assigned to the sprint on that day |
completed_tickets | Tickets in a done status category on that day |
remaining_tickets | total_tickets - completed_tickets |
Use this data to plot a burndown chart and spot trends early. A flat or rising
remaining_tickets line signals the sprint may be at risk.
8. Complete a Sprint
When the iteration is over, transition the sprint from Active to Completed:
curl -s -X POST "$BASE_URL/api/v1/sprints/$SPRINT_ID/complete" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 1",
"goal": "...",
"start_date": "...",
"end_date": "...",
"status": "Completed",
"created_at": "...",
"updated_at": "..."
}
The status changes to Completed. Any tickets still in progress remain in their
current status — they are not automatically moved. You can reassign
unfinished tickets to the next sprint.
CLI shortcut:
alloy sprint complete "$SPRINT_ID"
9. Delete a Sprint
Admins can delete a sprint. If the sprint has tickets assigned, the API returns
a 409 Conflict unless you pass ?cascade=true.
Preview what would be deleted with a dry-run:
curl -s -X DELETE "$BASE_URL/api/v1/sprints/$SPRINT_ID?cascade=true&dry_run=true" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint_id": "...",
"dependents": {
"tickets": 0
}
}
Then delete the sprint. With no dependents, a simple DELETE returns 204 No Content. If tickets are assigned, add ?cascade=true to remove them as well.
Note: Deleting a sprint is irreversible. Always use the dry-run option first to review what will be removed.
Learn More
- Projects & Tickets — create and manage the tickets that fill your sprints
- Workflows & Statuses — define the statuses tickets move through during a sprint
- Time Tracking & Finance — log hours against sprint tickets
- Running a Sprint (Playbook) — step-by-step sprint lifecycle from a PM’s perspective