API reference: projects and tasks
Read projects, their phases and milestones, and tasks; change a task's status, dates and checklist, and comment on it.
Last updated
Project and task endpoints need projects:read to read and projects:write to change. They return hours, never budgets in money or charges. Every sample reads the key from CURRENT_API_KEY and calls https://api.current.day/v1.
/v1/projectsNeeds the projects:read scope. Pages with a cursor.
Lists the projects this key can see, newest first, with number, status, health, company, sync mode, dates, progress and budgeted hours. It changes nothing and never shows money, rates or charges. Pages with a cursor, at most 100 a page.
Parameters
Query parameters
- company_iduuidOptional
- Only this company's projects.
- statustext, up to 40 charactersOptional
- Only projects in this status, such as active or completed.
- include_archivedtrue or falseOptional
- Include archived projects.
- limitinteger, 1 to 100Optional
- Rows per page, 1 to 100. 25 when left out.
- cursorcursorOptional
- next_cursor from the previous page.
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
curl -sS --fail-with-body "https://api.current.day/v1/projects?status=active&limit=10" \
-H "Authorization: Bearer $CURRENT_API_KEY"
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": [
{
"id": "9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73",
"name": {
"untrusted_text": "Lakeshore Dental: workstation refresh",
"source": "customer"
},
"number": null,
"status": "active",
"health": "on_track",
"sync_mode": "current_native",
"company_id": "c2e9a0f4-1b7d-4c35-a8e6-5d3f7b1c9e02",
"company_name": {
"untrusted_text": "Lakeshore Dental",
"source": "customer"
},
"lead_id": "8d4b6f1a-2c9e-4e73-b05d-7a1e3c5f9b48",
"lead_name": {
"untrusted_text": "Priya Okafor",
"source": "customer"
},
"due_date": "2026-11-28",
"started_at": "2026-11-02T13:00:00.000Z",
"completed_at": null,
"progress": 40,
"budget_hours": 24,
"archived_at": null,
"created_at": "2026-10-28T10:12:33.000Z",
"updated_at": "2026-11-06T17:20:45.000Z"
}
],
"next_cursor": null,
"has_more": false
}/v1/projects/{project_id}Needs the projects:read scope.
Reads one project with its phases, milestones and the hours planned and worked (hours only). It changes nothing and never shows money, rates or charges.
Parameters
Path parameters
- project_iduuidRequired
- The project's id (read it with GET /v1/projects).
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
curl -sS --fail-with-body "https://api.current.day/v1/projects/9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73" \
-H "Authorization: Bearer $CURRENT_API_KEY"
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"project": {
"id": "9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73",
"name": {
"untrusted_text": "Lakeshore Dental: workstation refresh",
"source": "customer"
},
"number": null,
"status": "active",
"health": "on_track",
"sync_mode": "current_native",
"company_id": "c2e9a0f4-1b7d-4c35-a8e6-5d3f7b1c9e02",
"company_name": {
"untrusted_text": "Lakeshore Dental",
"source": "customer"
},
"lead_id": "8d4b6f1a-2c9e-4e73-b05d-7a1e3c5f9b48",
"lead_name": {
"untrusted_text": "Priya Okafor",
"source": "customer"
},
"due_date": "2026-11-28",
"started_at": "2026-11-02T13:00:00.000Z",
"completed_at": null,
"progress": 40,
"budget_hours": 24,
"archived_at": null,
"created_at": "2026-10-28T10:12:33.000Z",
"updated_at": "2026-11-06T17:20:45.000Z",
"phases": [
{
"id": "1f6c8a3e-7d52-4b19-a4e6-0c9b2d5f8e31",
"name": {
"untrusted_text": "Build",
"source": "customer"
},
"position": 1,
"end_date": "2026-11-21"
}
],
"milestones": [
{
"id": "6a2e9c4f-8b15-4d73-9e60-2b7d1f5a3c84",
"name": {
"untrusted_text": "Go live",
"source": "customer"
},
"status": "backlog",
"end_date": "2026-11-28"
}
],
"hours": {
"planned": 24,
"worked": 9.5,
"tasks": 8,
"tasks_done": 3
}
}
}
}/v1/tasksNeeds the projects:read scope. Pages with a cursor.
Lists the tasks of one project or one assignee (give project_id, assignee_id or both), newest first, optionally in one status. It changes nothing and never shows money. Pages with a cursor, at most 100 a page.
Parameters
Query parameters
- project_iduuidOptional
- Only this project's tasks.
- assignee_iduuidOptional
- Only tasks assigned to this person.
- statusone of the values listedOptional
backlogin_progressreviewdone- limitinteger, 1 to 100Optional
- Rows per page, 1 to 100. 50 when left out.
- cursorcursorOptional
- next_cursor from the previous page.
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
curl -sS --fail-with-body "https://api.current.day/v1/tasks?project_id=9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73&status=in_progress" \
-H "Authorization: Bearer $CURRENT_API_KEY"
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": [
{
"id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"name": {
"untrusted_text": "Image the front desk workstations",
"source": "customer"
},
"status": "in_progress",
"number": null,
"project_id": "9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73",
"project_name": {
"untrusted_text": "Lakeshore Dental: workstation refresh",
"source": "customer"
},
"phase_id": "1f6c8a3e-7d52-4b19-a4e6-0c9b2d5f8e31",
"assignee_id": "8d4b6f1a-2c9e-4e73-b05d-7a1e3c5f9b48",
"assignee_name": {
"untrusted_text": "Priya Okafor",
"source": "staff"
},
"start_date": "2026-11-04",
"end_date": "2026-11-14",
"priority": "normal",
"is_milestone": false,
"progress": 50,
"estimated_hours": 6,
"worked_hours": 3,
"remaining_hours": 3,
"created_at": "2026-10-28T10:15:02.000Z",
"updated_at": "2026-11-06T17:20:45.000Z"
}
],
"next_cursor": null,
"has_more": false
}/v1/tasks/{task_id}Needs the projects:read scope.
Reads one task with its description, checklist, assignee and the tasks it waits on or that wait on it. It changes nothing and never shows money.
Parameters
Path parameters
- task_iduuidRequired
- The task's id (read it with GET /v1/tasks or GET /v1/me/tasks).
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
curl -sS --fail-with-body "https://api.current.day/v1/tasks/3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58" \
-H "Authorization: Bearer $CURRENT_API_KEY"
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"task": {
"id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"name": {
"untrusted_text": "Image the front desk workstations",
"source": "customer"
},
"status": "in_progress",
"number": null,
"project_id": "9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73",
"project_name": {
"untrusted_text": "Lakeshore Dental: workstation refresh",
"source": "customer"
},
"phase_id": "1f6c8a3e-7d52-4b19-a4e6-0c9b2d5f8e31",
"assignee_id": "8d4b6f1a-2c9e-4e73-b05d-7a1e3c5f9b48",
"assignee_name": {
"untrusted_text": "Priya Okafor",
"source": "staff"
},
"start_date": "2026-11-04",
"end_date": "2026-11-14",
"priority": "normal",
"is_milestone": false,
"progress": 50,
"estimated_hours": 6,
"worked_hours": 3,
"remaining_hours": 3,
"created_at": "2026-10-28T10:15:02.000Z",
"updated_at": "2026-11-06T17:20:45.000Z",
"description": {
"untrusted_text": "Image both front desk workstations with the standard build and test printing to reception.",
"source": "customer"
},
"sync_mode": "current_native",
"in_psa": false,
"checklist": [
{
"id": "c8f3b6e1-4a27-4e95-8d0c-1b5a7e3f9d62",
"label": {
"untrusted_text": "Label every cable at the front desk",
"source": "customer"
},
"done": false,
"position": 1,
"due_date": "2026-11-12",
"owner_id": "8d4b6f1a-2c9e-4e73-b05d-7a1e3c5f9b48"
}
],
"waits_on": [],
"waited_on_by": [
"6a2e9c4f-8b15-4d73-9e60-2b7d1f5a3c84"
]
}
}
}/v1/tasks/{task_id}Needs the projects:write scope.
Changes a task's status, dates, title or description. On a task synced with a PSA only a move into or out of done is taken here (the PSA's scheduled sync sends it), anything else answers change_in_current, and dates never move a task others wait on. Current never emails a customer about it.
Parameters
Path parameters
- task_iduuidRequired
- The task's id (read it with GET /v1/tasks or GET /v1/me/tasks).
Header parameters
- Idempotency-KeyuuidOptional
- The same uuid as request_id, if you prefer a header. Send one or the other, or both with the same value.
Body parameters
- request_iduuidOptional
- A uuid you mint for this change. Send the same one again with the same key to retry safely: Current answers the first answer and never writes twice. Kept 24 hours per key; a retry with another key, a rotated one included, runs again. Required unless the Idempotency-Key header is sent.
- statusone of the values listedOptional
backlogin_progressreviewdone- expected_statusone of the values listedOptional
- The status you last read: if it changed since, nothing changes and the answer is conflict.
backlogin_progressreviewdone- start_datetext, up to 10 charactersOptional
- A date, YYYY-MM-DD.
- end_datetext, up to 10 charactersOptional
- A date, YYYY-MM-DD.
- titletext, up to 500 charactersOptional
- descriptiontext, up to 15,000 charactersOptional
- An empty text clears it.
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 409 | conflictSomeone changed this first. Read it again, then retry. |
| 413 | bad_request (body_too_large)The request body is larger than 64 KB. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
REQUEST_ID=$(uuidgen) # a new id for this change; send the same one again only to retry it
curl -sS --fail-with-body -X PATCH "https://api.current.day/v1/tasks/3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58" \
-H "Authorization: Bearer $CURRENT_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{"request_id":"$REQUEST_ID","status":"review","expected_status":"in_progress"}
EOF
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"task_id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"status": "review",
"psa": "stays_in_current"
}
}/v1/me/tasksNeeds the projects:read scope.
Lists the open project tasks assigned to this key's holder, up to 100. It changes nothing and never shows money.
Parameters
No parameters.
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
curl -sS --fail-with-body "https://api.current.day/v1/me/tasks" \
-H "Authorization: Bearer $CURRENT_API_KEY"
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": [
{
"id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"name": {
"untrusted_text": "Image the front desk workstations",
"source": "customer"
},
"status": "in_progress",
"project_id": "9b5e1d7c-3a46-4f28-8c0b-6e2a9f4d1c73",
"project_name": {
"untrusted_text": "Lakeshore Dental: workstation refresh",
"source": "customer"
},
"project_number": null,
"start_date": "2026-11-04",
"end_date": "2026-11-14",
"priority": "normal",
"is_milestone": false,
"estimated_hours": 6,
"worked_hours": 3
}
]
}/v1/tasks/{task_id}/commentsNeeds the projects:write scope.
Adds an internal comment (plain text, up to 15,000 characters) to a task as this key's holder; partners and customers never see it, and it stays in Current. Retry with the same request_id and it is never added twice.
Parameters
Path parameters
- task_iduuidRequired
- The task's id (read it with GET /v1/tasks or GET /v1/me/tasks).
Header parameters
- Idempotency-KeyuuidOptional
- The same uuid as request_id, if you prefer a header. Send one or the other, or both with the same value.
Body parameters
- request_iduuidOptional
- A uuid you mint for this change. Send the same one again with the same key to retry safely: Current answers the first answer and never writes twice. Kept 24 hours per key; a retry with another key, a rotated one included, runs again. Required unless the Idempotency-Key header is sent.
- bodytext, up to 15,000 charactersRequired
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 409 | conflictSomeone changed this first. Read it again, then retry. |
| 413 | bad_request (body_too_large)The request body is larger than 64 KB. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
REQUEST_ID=$(uuidgen) # a new id for this change; send the same one again only to retry it
curl -sS --fail-with-body -X POST "https://api.current.day/v1/tasks/3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58/comments" \
-H "Authorization: Bearer $CURRENT_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{"request_id":"$REQUEST_ID","body":"Both workstations are imaged and printing works."}
EOF
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"comment_id": "5f2b8e4d-9c61-4a37-b8d5-0e3a7c1f6b92",
"task_id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"psa": "stays_in_current"
}
}/v1/tasks/{task_id}/checklistNeeds the projects:write scope.
Adds a checklist line to a task, with an optional due date that can never fall after the task's own. Current never emails a customer about it; retry with the same request_id and it is never added twice.
Parameters
Path parameters
- task_iduuidRequired
- The task's id (read it with GET /v1/tasks or GET /v1/me/tasks).
Header parameters
- Idempotency-KeyuuidOptional
- The same uuid as request_id, if you prefer a header. Send one or the other, or both with the same value.
Body parameters
- request_iduuidOptional
- A uuid you mint for this change. Send the same one again with the same key to retry safely: Current answers the first answer and never writes twice. Kept 24 hours per key; a retry with another key, a rotated one included, runs again. Required unless the Idempotency-Key header is sent.
- labeltext, up to 500 charactersRequired
- due_datetext, up to 10 charactersOptional
- A date, YYYY-MM-DD.
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 409 | conflictSomeone changed this first. Read it again, then retry. |
| 413 | bad_request (body_too_large)The request body is larger than 64 KB. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
REQUEST_ID=$(uuidgen) # a new id for this change; send the same one again only to retry it
curl -sS --fail-with-body -X POST "https://api.current.day/v1/tasks/3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58/checklist" \
-H "Authorization: Bearer $CURRENT_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{"request_id":"$REQUEST_ID","label":"Label every cable at the front desk","due_date":"2026-11-12"}
EOF
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"item_id": "c8f3b6e1-4a27-4e95-8d0c-1b5a7e3f9d62",
"task_id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"psa": "stays_in_current"
}
}/v1/tasks/{task_id}/checklist/{item_id}Needs the projects:write scope.
Ticks, unticks or renames one checklist line on a task. Current never emails a customer about it; retry with the same request_id and it is applied once.
Parameters
Path parameters
- task_iduuidRequired
- The task's id (read it with GET /v1/tasks or GET /v1/me/tasks).
- item_iduuidRequired
- The checklist line's id (read it with GET /v1/tasks/{task_id}).
Header parameters
- Idempotency-KeyuuidOptional
- The same uuid as request_id, if you prefer a header. Send one or the other, or both with the same value.
Body parameters
- request_iduuidOptional
- A uuid you mint for this change. Send the same one again with the same key to retry safely: Current answers the first answer and never writes twice. Kept 24 hours per key; a retry with another key, a rotated one included, runs again. Required unless the Idempotency-Key header is sent.
- donetrue or falseOptional
- labeltext, up to 500 charactersOptional
Errors
| Status | Code and meaning |
|---|---|
| 400 | bad_requestThe request was not in the expected shape. |
| 401 | unauthorizedThis token was not accepted. |
| 403 | not_allowed, frozen, module_offThis agent is not allowed to do that. This workspace is read only right now, so nothing can be changed. The API is not switched on for this workspace. |
| 404 | not_foundNothing was found with that id, or this agent cannot see it. |
| 405 | bad_request (method_not_allowed)That address does not accept this method. The Allow header lists the ones it does. |
| 409 | conflictSomeone changed this first. Read it again, then retry. |
| 413 | bad_request (body_too_large)The request body is larger than 64 KB. |
| 429 | rate_limited, send_cappedToo many requests from this token. Wait, then try again. This token has sent its limit of customer emails for now. Try again later. |
| 503 | degradedCurrent is busy. Try again in a minute. |
REQUEST_ID=$(uuidgen) # a new id for this change; send the same one again only to retry it
curl -sS --fail-with-body -X PATCH "https://api.current.day/v1/tasks/3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58/checklist/c8f3b6e1-4a27-4e95-8d0c-1b5a7e3f9d62" \
-H "Authorization: Bearer $CURRENT_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{"request_id":"$REQUEST_ID","done":true}
EOF
# A refusal exits non-zero and prints the error: read .error.code and .error.reason,
# for example with jq -r '.error.code, .error.reason'{
"data": {
"item_id": "c8f3b6e1-4a27-4e95-8d0c-1b5a7e3f9d62",
"task_id": "3d8a5f2c-1e69-4c07-b3d4-7f0e6a9c2b58",
"done": true,
"psa": "stays_in_current"
}
}