Review Timesheet
This endpoint records approve or reject decisions for each day of one or more timecards in a timesheet.
Endpoint
Section titled “Endpoint”POST /v1/timesheets/timesheets/reviewAuthentication
Section titled “Authentication”Include your API key in the x-api-key header. See Authentication.
Required Scope
Section titled “Required Scope”timesheets:reviewRequest Body
Section titled “Request Body”The request body is not validated against a schema. Send every field marked Required in the shape shown. A missing or malformed field usually causes a 500, not a 400.
| Field | Type | Required | Description |
|---|---|---|---|
timesheetId | string | Yes | Timesheet ID, for example tenant-123#user-a#20221231_20230106. Do not URL-encode it in the body. |
timecards | object[] | Yes | Review decisions, one item per timecard you review. |
sendEmails | boolean | No | When true, the API sends review result emails after saving the review. Defaults to false. |
userId | string | No | Timesheet owner’s user ID. It is only a fallback for finding the owner’s email address, and it is not recorded as the reviewer. |
Each review timecard:
| Field | Type | Required | Description |
|---|---|---|---|
projectId | string | Yes | Project ID of the timecard. |
taskId | string | Yes | Task ID of the timecard. |
data | object | Yes | One entry for each day: Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, and Friday. All seven keys are required. |
comments | string | null | No | Reviewer comments for the whole timecard. Returned as managerComments by Get Timesheet. |
Each day in data:
| Field | Type | Required | Description |
|---|---|---|---|
approved | boolean | Yes | true to approve the day, false to reject it. A missing value counts as rejected. |
rejectionReason | string | null | No | Reason for rejecting the day. The API does not require it for rejected days. |
date | string | Yes | The day’s date (YYYY-MM-DD). The API does not store it. The Friday date must be a valid date, or the API returns 500. |
There is no status field. The API derives each timecard’s status from its days:
- All seven days
approved: true: the timecard becomesapproved. - Any day not approved: the whole timecard becomes
rejected.
Example Request Body
Section titled “Example Request Body”In this example, Thursday is rejected, so the timecard becomes rejected.
{ "timesheetId": "tenant-123#user-a#20221231_20230106", "sendEmails": true, "timecards": [ { "projectId": "project-mno123pqr4567890", "taskId": "task-pqr123stu4567890", "comments": "Please fix Thursday and resubmit.", "data": { "Saturday": { "date": "2022-12-31", "approved": true, "rejectionReason": null }, "Sunday": { "date": "2023-01-01", "approved": true, "rejectionReason": null }, "Monday": { "date": "2023-01-02", "approved": true, "rejectionReason": null }, "Tuesday": { "date": "2023-01-03", "approved": true, "rejectionReason": null }, "Wednesday": { "date": "2023-01-04", "approved": true, "rejectionReason": null }, "Thursday": { "date": "2023-01-05", "approved": false, "rejectionReason": "Please clarify the hours entered." }, "Friday": { "date": "2023-01-06", "approved": true, "rejectionReason": null } } } ]}Example Request
Section titled “Example Request”curl -X POST "https://api.crewsum.com/v1/timesheets/timesheets/review" \ -H "x-api-key: $CREWSUM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "timesheetId": "tenant-123#user-a#20221231_20230106", "sendEmails": true, "timecards": [ { "projectId": "project-mno123pqr4567890", "taskId": "task-pqr123stu4567890", "comments": "Please fix Thursday and resubmit.", "data": { "Saturday": { "date": "2022-12-31", "approved": true, "rejectionReason": null }, "Sunday": { "date": "2023-01-01", "approved": true, "rejectionReason": null }, "Monday": { "date": "2023-01-02", "approved": true, "rejectionReason": null }, "Tuesday": { "date": "2023-01-03", "approved": true, "rejectionReason": null }, "Wednesday": { "date": "2023-01-04", "approved": true, "rejectionReason": null }, "Thursday": { "date": "2023-01-05", "approved": false, "rejectionReason": "Please clarify the hours entered." }, "Friday": { "date": "2023-01-06", "approved": true, "rejectionReason": null } } } ] }'const response = await fetch( "https://api.crewsum.com/v1/timesheets/timesheets/review", { method: "POST", headers: { "x-api-key": process.env.CREWSUM_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ timesheetId: "tenant-123#user-a#20221231_20230106", sendEmails: true, timecards: [ { projectId: "project-mno123pqr4567890", taskId: "task-pqr123stu4567890", comments: "Please fix Thursday and resubmit.", data: { Saturday: { date: "2022-12-31", approved: true, rejectionReason: null }, Sunday: { date: "2023-01-01", approved: true, rejectionReason: null }, Monday: { date: "2023-01-02", approved: true, rejectionReason: null }, Tuesday: { date: "2023-01-03", approved: true, rejectionReason: null }, Wednesday: { date: "2023-01-04", approved: true, rejectionReason: null }, Thursday: { date: "2023-01-05", approved: false, rejectionReason: "Please clarify the hours entered." }, Friday: { date: "2023-01-06", approved: true, rejectionReason: null }, }, }, ], }), },);const result = await response.json();POST /v1/timesheets/timesheets/review HTTP/1.1Host: api.crewsum.comx-api-key: <your-api-key>Content-Type: application/json
{ "timesheetId": "tenant-123#user-a#20221231_20230106", "sendEmails": true, "timecards": [ { "projectId": "project-mno123pqr4567890", "taskId": "task-pqr123stu4567890", "comments": "Please fix Thursday and resubmit.", "data": { "Saturday": { "date": "2022-12-31", "approved": true, "rejectionReason": null }, "Sunday": { "date": "2023-01-01", "approved": true, "rejectionReason": null }, "Monday": { "date": "2023-01-02", "approved": true, "rejectionReason": null }, "Tuesday": { "date": "2023-01-03", "approved": true, "rejectionReason": null }, "Wednesday": { "date": "2023-01-04", "approved": true, "rejectionReason": null }, "Thursday": { "date": "2023-01-05", "approved": false, "rejectionReason": "Please clarify the hours entered." }, "Friday": { "date": "2023-01-06", "approved": true, "rejectionReason": null } } } ]}Response
Section titled “Response”On success, the API returns HTTP 200 OK.
Example Response
Section titled “Example Response”{ "message": "Successfully reviewed timesheet"}Behavior
Section titled “Behavior”- For each timecard in the request, the API stores the day decisions and rejection reasons, the derived status,
comments, and the review time (reviewedAt). - Timecards left out of the request are not changed.
approverNameandapproverEmailare set tonullfor reviews made through the API.- The approval links that were emailed for the reviewed timecards stop working.
- A rejected timecard lets the user submit the timesheet again. See Submit Self Timesheet.
- When
sendEmailsistrue, the API emails the review result to the user, to project contacts whose notification level is copy only or copy with link, to the user’s supplier contacts, and to your internal copy address if it is turned on. - The API first checks that the timesheet is in your account. If it is not, the API returns
404and writes nothing. - The review is saved before emails are sent. If sending emails fails, the API returns
500, but the review is kept and no webhook is sent. - After the review, Crewsum sends the
timecards.reviewedwebhook event. The payload is{ "timecards": [{ "timecard": <timecard>, "review": <review> }] }, with one item per reviewed timecard.
Error Responses
Section titled “Error Responses”| Status | Meaning |
|---|---|
404 | No timesheet in your account has this ID. Nothing is written. Message: Timesheet with ID <id> not found. |
500 | The review could not be saved, for example because a day key is missing or the Friday date is not valid. Message: Error updating timecards. |
500 | The review was saved, but a later step failed, such as sending emails. Message: Error submitting timesheet review. |
500 | The body is missing or has the wrong shape, for example no timecards array. The response has a generic error body. |
Authentication and scope failures are described in Errors.
Related Webhooks
Section titled “Related Webhooks” timecards.reviewed View webhook event details.