Complete reference for TaskFlow.Api REST endpoints.
Local Development:
- Direct run:
https://localhost:{port}(port shown in console) - Docker:
http://localhost:8080
Production:
- API:
https://taskflow-api.skalaforge.com - Web:
https://taskflow.skalaforge.com
Currently, no authentication is required. All endpoints are publicly accessible.
All endpoints accept and return application/json.
The snippets below describe the currently implemented contract additions used by the Journal and Tasks screens.
TaskItemResponseDto now includes assignment, movement, and hierarchy metadata in addition to core task fields:
currentJournalEntryId: number | nullcurrentJournalDate: string | null(ISO date)firstTaggedDate: string | null(ISO date)lastMovedDate: string | null(ISO date)daysTagged: numbermoveCount: numberparentTaskItemId: number | nullchildTaskCount: number
POST /api/v1/TaskItems accepts optional journalDate:
{
"title": "Prepare demo",
"status": "todo",
"journalDate": "2026-05-20"
}Behavior:
- If
journalDateis in the past, returns422withTASK_CREATION_PAST_DAY_NOT_ALLOWED. - If
journalDateis today/future, the task is automatically assigned to that journal day.
GET /api/v1/TaskItems/{id}/history returns timeline entries (TaskItemEventResponseDto[]) in chronological order.
Task parent/child updates return machine-readable error payloads (code, message, details?) for:
TASK_PARENT_NOT_FOUNDTASK_PARENT_SELF_NOT_ALLOWEDTASK_PARENT_DEPTH_NOT_ALLOWED(one subtask level only)TASK_PARENT_CYCLE_NOT_ALLOWEDTASK_PARENT_COMPLETE_BLOCKED_BY_CHILDRENTASK_PARENT_DELETE_BLOCKED_BY_CHILDRENTASK_REOPEN_PAST_DAY_NOT_ALLOWED
PUT /api/v1/TaskItems/{id} accepts optional timezoneOffsetMinutes (minutes to add to UTC to get the user's local time; negative west of UTC, e.g. -300 for US Central CDT). When a completed task is reopened, the offset is used to compute the user's local today for the past-day guard. A task assigned to the user's local today can be reopened; an earlier assigned date returns 422 TASK_REOPEN_PAST_DAY_NOT_ALLOWED (the response details include the task's assignedDate). If timezoneOffsetMinutes is omitted, the guard falls back to the UTC date.
Retrieves all task items with status information.
Endpoint: GET /api/v1/TaskItems
Response: 200 OK
[
{
"id": 1,
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"statusName": "To Do"
},
{
"id": 2,
"title": "Deploy to Azure",
"description": "Set up production environment",
"statusName": "Done"
}
]Example:
curl http://localhost:8080/api/v1/TaskItemsRetrieves a specific task item with status information.
Endpoint: GET /api/v1/TaskItems/{id}
Parameters:
id(path, integer, required) - Task item ID
Response: 200 OK
{
"id": 1,
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"statusName": "To Do"
}Error Response: 404 Not Found
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}Example:
curl http://localhost:8080/api/v1/TaskItems/1Creates a new task item with status assignment.
Endpoint: POST /api/v1/TaskItems
Request Body:
{
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"statusId": 1
}Fields:
title(string, required, max 100 chars) - Task titledescription(string, optional) - Task descriptionstatusId(integer, optional, defaults to 1) - Status ID to assign
Response: 201 Created
{
"id": 3,
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"statusName": "To Do"
}Location Header: /api/v1/TaskItems/3
Validation Error: 400 Bad Request
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Title": ["Title is required"]
}
}Example:
curl -X POST http://localhost:8080/api/v1/TaskItems \
-H "Content-Type: application/json" \
-d '{
"title": "New Task",
"description": "Task description",
"statusId": 1
}'Updates an existing task item, including status assignment.
Endpoint: PUT /api/v1/TaskItems/{id}
Parameters:
id(path, integer, required) - Task item ID to update
Request Body:
{
"title": "Updated task title",
"description": "Updated description",
"statusId": 2
}Fields:
title(string, required, max 100 chars) - Task titledescription(string, optional) - Task descriptionstatusId(integer, required) - Status ID to assign
Response: 200 OK
{
"id": 1,
"title": "Updated task title",
"description": "Updated description",
"statusName": "In Progress"
}Error Responses:
404 Not Found - Task doesn't exist
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}400 Bad Request - Validation failure
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Title": ["Title cannot exceed 100 characters"]
}
}Example:
curl -X PUT http://localhost:8080/api/v1/TaskItems/1 \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Title",
"description": "Updated description",
"statusId": 2
}'Updates only the fields present in the request body (JSON Merge Patch semantics).
Endpoint: PATCH /api/v1/TaskItems/{id}
Request Body: any subset of title, description, status, priority, dueDate, parentTaskItemId, autoCompleteParentWhenChildrenDone, timezoneOffsetMinutes.
- An omitted field is left unchanged and writes no history event.
- An explicit
nullclearsdescription,dueDateorparentTaskItemId. statusorpriorityset tonullor omitted means unchanged.- An empty
titlereturns400 Bad Request; an unknown id returns404 Not Found. - Completion is set only through
status(Completed);isCompleteis not part of the contract and is ignored if sent.
Example:
curl -X PATCH http://localhost:8080/api/v1/TaskItems/1 \
-H "Content-Type: application/json" \
-d '{"title": "Renamed"}'Deletes a task item.
Endpoint: DELETE /api/v1/TaskItems/{id}
Parameters:
id(path, integer, required) - Task item ID to delete
Response: 204 No Content
Error Response: 404 Not Found
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}Example:
curl -X DELETE http://localhost:8080/api/v1/TaskItems/1Retrieves all status items.
Endpoint: GET /api/v1/Status
Response: 200 OK
[
{
"id": 1,
"name": "To Do",
"description": "Task has not been started"
},
{
"id": 2,
"name": "In Progress",
"description": "Task is currently being worked on"
},
{
"id": 3,
"name": "Done",
"description": "Task has been completed"
}
]Example:
curl http://localhost:8080/api/v1/StatusRetrieves a specific status item.
Endpoint: GET /api/v1/Status/{id}
Parameters:
id(path, integer, required) - Status item ID
Response: 200 OK
{
"id": 1,
"name": "To Do",
"description": "Task has not been started"
}Error Response: 404 Not Found
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}Example:
curl http://localhost:8080/api/v1/Status/1Creates a new status item.
Endpoint: POST /api/v1/Status
Request Body:
{
"name": "In Review",
"description": "Task is under review"
}Fields:
name(string, required, max 50 chars) - Status name (must be unique)description(string, optional, max 200 chars) - Status description
Response: 201 Created
{
"id": 4,
"name": "In Review",
"description": "Task is under review"
}Location Header: /api/v1/Status/4
Validation Error: 400 Bad Request
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Name": ["Status name is required"],
"Description": ["Status description cannot exceed 200 characters"]
}
}Example:
curl -X POST http://localhost:8080/api/v1/Status \
-H "Content-Type: application/json" \
-d '{
"name": "In Review",
"description": "Task is under review"
}'Updates an existing status item.
Endpoint: PUT /api/v1/Status/{id}
Parameters:
id(path, integer, required) - Status item ID to update
Request Body:
{
"name": "Under Review",
"description": "Task is being reviewed by the team"
}Fields:
name(string, required, max 50 chars) - Status name (must be unique)description(string, optional, max 200 chars) - Status description
Response: 200 OK
Example response:
{
"id": 42,
"name": "Under Review",
"description": "Task is being reviewed by the team"
}
**Error Responses:**
`404 Not Found` - Status doesn't exist
```json
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}400 Bad Request - Validation failure
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Name": [
"Status name cannot exceed 50 characters",
"A status with the same name already exists."
]
}
}Example:
curl -X PUT http://localhost:8080/api/v1/Status/4 \
-H "Content-Type: application/json" \
-d '{
"name": "Under Review",
"description": "Task is being reviewed by the team"
}'Deletes a status item.
Endpoint: DELETE /api/v1/Status/{id}
Parameters:
id(path, integer, required) - Status item ID to delete
Response: 204 No Content
Error Response: 404 Not Found
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404
}Example:
curl -X DELETE http://localhost:8080/api/v1/Status/4Returns comprehensive health status including all registered checks.
Endpoint: GET /health
Response: 200 OK (Healthy) or 503 Service Unavailable (Unhealthy)
{
"status": "Healthy",
"totalDuration": 25.4551,
"results": [
{
"name": "database",
"status": "Healthy",
"description": "",
"duration": 20.355,
"exception": null,
"data": null
},
{
"name": "self",
"status": "Healthy",
"description": "Application is running",
"duration": 1.0933,
"exception": null,
"data": null
}
]
}Use case: General health monitoring, load balancer health checks
Example:
curl http://localhost:8080/healthIndicates if the application is ready to receive traffic.
Endpoint: GET /health/ready
Response: 200 OK (Ready) or 503 Service Unavailable (Not Ready)
{
"status": "Healthy",
"totalDuration": 43.2066,
"results": [
{
"name": "database",
"status": "Healthy",
"description": "",
"duration": 40.8122,
"exception": null,
"data": null
}
]
}Use case: Kubernetes readiness probes, load balancer registration
Example:
curl http://localhost:8080/health/readyIndicates if the application is alive and responsive.
Endpoint: GET /health/live
Response: 200 OK (Alive) or 503 Service Unavailable (Dead)
{
"status": "Healthy",
"totalDuration": 0.1649,
"results": [
{
"name": "self",
"status": "Healthy",
"description": "Application is running",
"duration": 0.0911,
"exception": null,
"data": null
}
]
}Use case: Kubernetes liveness probes, restart decisions
Example:
curl http://localhost:8080/health/live| Status Code | Meaning | When Used |
|---|---|---|
200 OK |
Success | GET requests successful |
201 Created |
Resource created | POST successful |
204 No Content |
Success with no body | PUT, DELETE successful |
400 Bad Request |
Validation error | Invalid input data |
404 Not Found |
Resource not found | Requested item doesn't exist |
500 Internal Server Error |
Server error | Unexpected server-side error |
503 Service Unavailable |
Service unhealthy | Health check failure |
All error responses follow RFC 7807 Problem Details format:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"FieldName": ["Error message"]
}
}Title:
- Required
- Maximum 200 characters
- Cannot be empty or whitespace
Description:
- Optional
- Maximum 1000 characters when provided
Status:
- Optional on create and update; an omitted value keeps the stored status
- Completion is expressed only through
Completed; there is noisCompletefield
Name:
- Required
- Maximum 50 characters
- Must be unique across all statuses
- Cannot be empty or whitespace
Description:
- Optional
- Maximum 200 characters when provided
In Development mode, interactive API documentation is available via Swagger UI.
Access Swagger:
- Local: Navigate to
https://localhost:{port}orhttp://localhost:8080 - Features:
- Interactive endpoint testing
- Request/response examples
- Schema definitions
- Try it out functionality
Note: Swagger is disabled in Production mode for security and performance.
A pre-configured Postman collection is available for testing:
Setup:
- Import collection in Postman: File → Import → paste URL
- Create environment with variable:
- Name:
baseUrl - Value:
http://localhost:8080(or your deployment URL)
- Name:
- Run requests from the collection
Currently, no rate limiting is implemented. All clients can make unlimited requests.
CORS is configured to allow all origins in Development mode. For production deployments, configure specific allowed origins in Program.cs.
The current API does not implement pagination. All GET requests return all matching records.
Future enhancement: Consider adding pagination for large datasets:
GET /api/TaskItems?page=1&pageSize=20
Currently not implemented. All tasks are returned in database order.
Future enhancements:
GET /api/TaskItems?status=Completed
GET /api/TaskItems?sortBy=createdAt&order=desc
# 1. Create a task
TASK_ID=$(curl -s -X POST http://localhost:8080/api/TaskItems \
-H "Content-Type: application/json" \
-d '{"title":"New Task","description":"Description"}' \
| jq -r '.id')
echo "Created task with ID: $TASK_ID"
# 2. Get the task
curl http://localhost:8080/api/TaskItems/$TASK_ID
# 3. Update the task
curl -X PUT http://localhost:8080/api/TaskItems/$TASK_ID \
-H "Content-Type: application/json" \
-d '{"title":"Updated Task","description":"Updated description"}'
# 4. Get all tasks
curl http://localhost:8080/api/TaskItems
# 5. Delete the task
curl -X DELETE http://localhost:8080/api/TaskItems/$TASK_ID
# 6. Verify deletion (should return 404)
curl -I http://localhost:8080/api/TaskItems/$TASK_ID# 1. Create a task with status
TASK_ID=$(curl -s -X POST http://localhost:8080/api/v1/TaskItems \
-H "Content-Type: application/json" \
-d '{"title":"New Task","description":"Description","statusId":1}' \
| jq -r '.id')
echo "Created task with ID: $TASK_ID"
# 2. Get the task (includes statusName)
curl http://localhost:8080/api/v1/TaskItems/$TASK_ID
# 3. Update the task with new status
curl -X PUT http://localhost:8080/api/v1/TaskItems/$TASK_ID \
-H "Content-Type: application/json" \
-d '{"title":"Updated Task","description":"Updated description","statusId":2}'
# 4. Get all tasks
curl http://localhost:8080/api/v1/TaskItems
# 5. Delete the task
curl -X DELETE http://localhost:8080/api/v1/TaskItems/$TASK_ID
# 6. Verify deletion (should return 404)
curl -I http://localhost:8080/api/v1/TaskItems/$TASK_ID# 1. Create a status
STATUS_ID=$(curl -s -X POST http://localhost:8080/api/v1/Status \
-H "Content-Type: application/json" \
-d '{"name":"In Review","description":"Task is under review"}' \
| jq -r '.id')
echo "Created status with ID: $STATUS_ID"
# 2. Get the status
curl http://localhost:8080/api/v1/Status/$STATUS_ID
# 3. Update the status
curl -X PUT http://localhost:8080/api/v1/Status/$STATUS_ID \
-H "Content-Type: application/json" \
-d '{"name":"Under Review","description":"Task is being reviewed by the team"}'
# 4. Get all statuses
curl http://localhost:8080/api/v1/Status
# 5. Delete the status
curl -X DELETE http://localhost:8080/api/v1/Status/$STATUS_ID
# 6. Verify deletion (should return 404)
curl -I http://localhost:8080/api/v1/Status/$STATUS_ID# Check overall health
curl http://localhost:8080/health | jq '.status'
# Check readiness (database connectivity)
curl http://localhost:8080/health/ready | jq '.status'
# Check liveness (application responsiveness)
curl http://localhost:8080/health/live | jq '.status'
# Get health check details
curl http://localhost:8080/health | jq '.results'- Getting Started Guide - Setup and local testing
- Architecture Documentation - API design and patterns
- Deployment Guide - Deploying to different environments