Saves or submits the caller's answers to a performance review. Required scope: w_reviews.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
This endpoint uses thew_reviewsscope, which must be enabled through the Integrations section found within the Settings menu.
Requires a user token, or an account token together with the member_id query parameter, whose employee is the reviewer of the review. For a self review, that is the reviewee. For a manager review, it is the manager. For peer and upward reviews, it is the assigned reviewer. An account token without member_id gets 403 Account tokens need a member_id for this operation.
Use GET /review-cycles/:reviewCycleId/reviews/:id to read the questionnaire and its question ids. The write_url returned there and by the tasks endpoint points to this endpoint.
Preconditions:
- The review cycle must be
active. - The review must not be
submittedyet.
Only the questions listed in answers are changed, and existing answers to other questions are kept. With action: "save" the review is stored as draft. With action: "submit" it moves to submitted and can no longer be edited. Submitting is rejected when any of these is true:
- a mandatory question is unanswered
- rating is enabled for the review type and no overall rating is provided, either through
ratingor the overall-rating question
Request body
{
"action": "submit",
"rating": 4,
"answers": [
{
"question_id": "2501297d-e22b-5f57-bbeb-21490ee0c212",
"answer": "Delivered three major projects on time."
},
{
"question_id": "2501297b-1920-5e4c-b21b-fc3caf56b195",
"choices": ["4"]
},
{
"question_id": "2501297b-1920-5e4c-b21b-fc3caf56b335",
"choices": ["4"]
}
]
}| key | type | description |
|---|---|---|
| action | string | save (store as draft) or submit (store and submit) (required) |
| rating | integer | Overall rating of the review. Optional, may be null. When omitted, the choice of the overall-rating question is used |
| answers | array | Answers to apply (required, may be empty) |
| answers[].question_id | string | UUID of a question of this review's questionnaire (required) |
| answers[].answer | string | Free-text answer. HTML tags are stripped. null or "" clears the answer |
| answers[].choices | array of string | Selected choice keys or rating values (e.g. ["4"]) for rated and choice questions. For a section_rating question this also sets the section's rating |
Results
Returns 200 with the review and its questionnaire, including the persisted answers. The shape is the same as GET /review-cycles/:reviewCycleId/reviews/:id. Choice values are returned as labels when the question defines choice labels. After submission, write_url is null.
{
"review": {
"id": "4d4",
"type": "manager",
"status": "ready",
"master_template_id": "1001",
"follower_template_id": null,
"update_form_url": "/spi/v3/review-cycles/4d3/tasks/4d3/forms/manager",
"state": "submitted",
"submit_deadline": "2024-11-20T00:00:00.000Z",
"share_deadline": "2024-11-25T00:00:00.000Z",
"write_url": null
},
"questionnaire": {
"template_id": "2",
"overall_rating": 4,
"sections": [
{
"id": "2501299e-4332-59e9-8979-93bdc5aceaa9",
"name": "<p>Goals</p>",
"rating": 4,
"questions": [
{
"id": "2501297d-e22b-5f57-bbeb-21490ee0c212",
"body": "<p>What progress has the employee made toward their goals?</p>",
"position": 0,
"section_id": "2501299e-4332-59e9-8979-93bdc5aceaa9",
"answer": "Delivered three major projects on time.",
"type": "paragraph"
},
{
"id": "2501297b-1920-5e4c-b21b-fc3caf56b195",
"body": "<p>Section Rating</p>",
"position": 1,
"section_id": "2501299e-4332-59e9-8979-93bdc5aceaa9",
"answer": null,
"type": "numeric_rated",
"metadata": {
"mandatory": true,
"semantic_type": "section_rating",
"rating_options": {}
},
"choices": ["4"]
}
]
},
{
"id": "25012984-7b5b-57df-86ce-43d640f23610",
"name": "<p>Overall rating</p>",
"rating": null,
"questions": [
{
"id": "2501297b-1920-5e4c-b21b-fc3caf56b335",
"body": "<p>Overall rating</p>",
"position": 0,
"section_id": "25012984-7b5b-57df-86ce-43d640f23610",
"answer": null,
"type": "numeric_rated",
"metadata": {
"mandatory": true,
"semantic_type": "overall_rating",
"rating_options": {}
},
"choices": ["4"]
}
]
}
]
}
}| key | type | description |
|---|---|---|
| review.state | string | not_started, draft or submitted |
| review.submit_deadline | string | Deadline for submitting the review |
| review.share_deadline | string | Deadline for sharing the review aggregate |
| review.write_url | string | Relative URL of this endpoint, or null once the review is submitted |
| questionnaire.overall_rating | number | Overall rating of the review |
| questionnaire.sections[].rating | number | Section rating |
| questionnaire.sections[].questions[].answer | string | Free-text answer |
| questionnaire.sections[].questions[].choices | array | Selected choices |
Error responses
| Status | Condition |
|---|---|
| 400 | Validation failed: missing or invalid action, missing answers, non-UUID question_id, non-integer rating. The body is keyed by field, e.g. {"action": {"code": "any.only", "message": "\"action\" must be one of [save, submit]"}} |
| 400 | {"message": "Question <question_id> does not belong to this review"} |
| 400 | {"message": "Notes cannot be empty for submitted or shared reviews", "code": "review.notes_empty_when_submitted_or_shared"}: submitting with unanswered mandatory questions |
| 400 | {"message": "Rating is required for submitted or shared reviews", "code": "review.rating_value_required"}: submitting without an overall rating when rating is enabled |
| 401 | Missing or invalid token |
| 403 | Missing w_reviews scope, account token without member_id, or the caller is not the reviewer (plain-text Forbidden) |
| 404 | {"message": "Review not found"}: the review does not exist, is deleted, belongs to another cycle, or the cycle is archived / deleted |
| 409 | {"message": "Review cycle is not open for writing"}: the cycle is not active |
| 409 | {"message": "Review has already been submitted"} |
