Create a deny
/api/v1/deniesRefuses permission_keys to a target at node_id and every node beneath it, checked before any grant: no role held anywhere, and no grant made lower down, can undo it. The target is an identity, a machine client (oauth_client, by its row id), or a role, which binds everyone holding it wherever they hold it. Holders of an exception_role_ids role keep access wherever they hold it, while that assignment is in effect; use one so the people who manage access are not locked out. A reason is required. A deny is never edited: to change one, delete it and create another. Canopy's own routes refuse from the next request; an SDK within its cache window. Preview it first with POST /denies/preview, which takes the same body. Writes a deny.created audit row and webhook event. Requires deny.manage; a person as the target also needs the right to see the Environment's people.
Authentication
Authorization Option A JWT access token. Never send alongside X-API-Key: a request carrying both is refused.
X-API-Key Option B API key for management-tier access. Never send alongside an Authorization header: a request carrying both is refused.
Request body
application/json
target_typeenum Required What the deny targets: one identity, one machine client (`oauth_client`), or every holder of a role, wherever they hold it.
target_idstring · uuid Required The identity, the machine client's row id, or the role it targets.
permission_keysstring[] Required The permission keys it refuses, each in the Environment's catalog.
node_idstring · uuid Required The node it applies at. It refuses there and at every node beneath, and no grant lower down can undo it.
exception_role_idsstring[] Optional Roles whose holders keep access despite the deny, wherever they hold them, while that assignment is in effect. Use one so the people who manage access are not locked out.
reasonstring Required Why the deny exists. Required: it is the record an auditor reads.
Responses
application/json
data *DenyResponseDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
Returned object
curl -X POST "https://auth.canopy-io.com/api/v1/denies" \ -H "X-API-Key: $CANOPY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "target_type": "identity", "target_id": "00000000-0000-0000-0000-000000000000", "permission_keys": [ "documents.view" ], "node_id": "00000000-0000-0000-0000-000000000000", "exception_role_ids": [ "string" ], "reason": "Office A files are under legal hold." }'
{ "data": { "id": "00000000-0000-0000-0000-000000000000", "target": { "type": "identity", "id": "00000000-0000-0000-0000-000000000000", "name": "string", "email": "string" }, "permission_keys": [ "documents.view" ], "node": { "id": "00000000-0000-0000-0000-000000000000", "name": "string", "path": [ "string" ] }, "exception_roles": [ { "id": "00000000-0000-0000-0000-000000000000", "name": "string" } ], "reason": "string", "created_by": { "type": "user", "id": "00000000-0000-0000-0000-000000000000", "name": "string" }, "created_at": "2026-04-20T12:00:00.000Z" } }
Tell us how we can improve this guide.