Remove controls from a project’s scope#
Description#
Remove up to 250 controls from a project’s scope, identified by scope-entry id (ScopedControl.id from the scoped-controls list, not the control’s own id). Removal is soft: removed controls stay visible in the scoped-controls list with a removedFromScope status. A rationale is required and recorded against every entry in the request as its scopeRationale, replacing any earlier one; it is separate from the project-level scopingRationale. The operation is idempotent: an entry that is already removed stays removed and takes the new rationale, so a retried request leaves the same state and returns the same response. An id that doesn’t match a scope entry in the project is skipped. Returns the matched entries in request order, in their resulting state. After a timeout, read the scoped-controls list or retry the same request. Supported only for Independent Controls Testing projects; a request against any other project type returns 409 with code unsupportedProjectType.
POST /assuranceProjects/{id}/scopedControls/removal
Required OAuth Scopes
grc:write
Parameters#
Parameter |
In |
Type |
Required |
Description |
|---|---|---|---|---|
X-Version |
header |
string |
true |
Version of the API (2026-09-01.grc.preview) |
body |
body |
true |
||
Wk-Workspace |
header |
string |
true |
The id of the Workiva workspace to operate in. Authorization is enforced against the authenticated user’s access within this workspace. |
id |
path |
string |
true |
The unique system identifier of the resource. |
Body parameter example#
{
"data": [
"019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90"
],
"rationale": "Below materiality threshold for FY26."
}
Code Samples#
curl -X POST 'https://api.app.wdesk.com/assuranceProjects/{id}/scopedControls/removal' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Wk-Workspace: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d' \
-H 'Authorization: Bearer {access-token}' \
-H 'X-Version: 2026-09-01.grc.preview' \
--data-raw '{"data":["019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90"],"rationale":"Below materiality threshold for FY26."}'
echo '{"data":["019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90"],"rationale":"Below materiality threshold for FY26."}' | http POST https://api.app.wdesk.com/assuranceProjects/{id}/scopedControls/removal \
X-Version:2026-09-01.grc.preview \
Content-Type:application/json \
Accept:application/json \
Wk-Workspace:1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d \
Authorization:"Bearer {access-token}"
wget --method=POST "https://api.app.wdesk.com/assuranceProjects/{id}/scopedControls/removal" \
--output-document - \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Wk-Workspace: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d' \
--header 'Authorization: Bearer {access-token}' \
--header 'X-Version: 2026-09-01.grc.preview' \
--body-data='{"data":["019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90"],"rationale":"Below materiality threshold for FY26."}'
import requests
headers = {
'X-Version': '2026-09-01.grc.preview',
'Content-Type': 'application/json',
'Accept': 'application/json',
'Wk-Workspace': '1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
'Authorization': 'Bearer {access-token}'
}
body = {
"data": [
"019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90"
],
"rationale": "Below materiality threshold for FY26."
}
r = requests.post('https://api.app.wdesk.com/assuranceProjects/{id}/scopedControls/removal', headers = headers, json=body)
print(r.json())
Returns#
200 - The scope entries of the requested ids after the removal.#
The scope entries a scope change affected, in their resulting state and in request order. For an add, only the entries the call created, each with its assigned ScopedControl.id and an inScope status. Removed and restored entries reflect their new status and rationale. Ids that don’t resolve are omitted. Not paginated.
400 - The request was invalid.#
Error response indicating the service could not process the request.
401 - Authentication is missing or invalid.#
Error response indicating the service could not process the request.
403 - The caller is not permitted to access this resource.#
Error response indicating the service could not process the request.
404 - The requested resource was not found.#
Error response indicating the service could not process the request.
409 - The request conflicts with the state of the target resource, for example an operation attempted on an unsupported project type.#
Error response indicating the service could not process the request.
429 - The rate limit has been exceeded.#
Error response indicating the service could not process the request.
500 - An unexpected error occurred.#
Error response indicating the service could not process the request.
Example Responses#
{
"data": [
{
"controlSnapshot": {
"controlId": "COSO-C-001",
"evergreenControlId": "019cafc7-4901-7181-a53b-b2263115961d",
"id": "01a0b15e-3c4d-7e5f-8a9b-0c1d2e3f4a5b",
"name": "Code of Conduct and Ethics Policy"
},
"id": "019cb0a1-2f3e-7c22-9a10-4d5e6f7a8b90",
"scopeRationale": "Below materiality threshold for FY26.",
"scopeStatus": "removedFromScope"
}
]
}
{
"code": "invalidFilter",
"message": "The $filter value could not be parsed.",
"target": "$filter"
}
{
"code": "unauthenticated",
"message": "Authentication credentials were missing or invalid."
}
{
"code": "permissionDenied",
"message": "You do not have permission to access this resource."
}
{
"code": "notFound",
"message": "No resource with this id was found."
}
{
"code": "unsupportedProjectType",
"message": "This operation is only supported for Independent Controls Testing projects.",
"target": "/type"
}
{
"code": "rateLimitExceeded",
"message": "Rate limit exceeded. Retry after the period indicated in the response headers."
}
{
"code": "internalError",
"message": "An unexpected error occurred. Please try again later."
}