Reviews
Review packets are generated when the Decay Engine determines that an access grant has decayed below the configured threshold. Reviewers evaluate the evidence and decide whether to confirm, revoke, or escalate the access.
ReviewPacket Schema
| Field |
Type |
Description |
id |
UUID |
Review packet identifier. |
principal_id |
UUID |
The principal whose access is under review. |
asset_id |
UUID |
The asset being reviewed. |
access_grant_ids |
UUID[] |
Grant IDs included in this review. |
decay_score |
float |
Decay score at the time the review was generated. |
risk_level |
enum |
CRITICAL · HIGH · MEDIUM · LOW |
evidence_json |
object |
Supporting evidence (usage stats, peer comparison, etc.). |
recommendation |
enum |
System recommendation: REVOKE · REVIEW · CONFIRM |
assigned_to_id |
UUID |
Verity ID of the assigned reviewer. |
workflow_id |
UUID |
Associated workflow instance (nullable). |
status |
enum |
PENDING · DECIDED · EXPIRED · ESCALATED |
due_at |
datetime |
Review deadline. |
created_at |
datetime |
When the review packet was generated. |
List Reviews
Retrieve a paginated list of review packets with optional filters.
Query Parameters
| Parameter |
Type |
Default |
Description |
status |
string |
— |
Filter by status: PENDING, DECIDED, EXPIRED, ESCALATED. |
risk_level |
string |
— |
Filter by risk level: CRITICAL, HIGH, MEDIUM, LOW. |
due_before |
datetime |
— |
Only return reviews due before this date (ISO 8601). |
cursor |
string |
— |
Pagination cursor from a previous response. |
limit |
integer |
50 |
Items per page (max 100). |
Example Request
curl -s "http://localhost:8000/v1/reviews?status=PENDING&risk_level=HIGH&limit=2" \
-H "Authorization: Bearer $TOKEN"
Example Response
{
"items": [
{
"id": "019f6b7c-8d9e-7000-8000-000000006001",
"principal_id": "019f1a2b-3c4d-7000-8000-000000000002",
"asset_id": "019f3d4e-5f60-7000-8000-000000000100",
"access_grant_ids": [
"019f2c3d-4e5f-7000-8000-000000000020"
],
"decay_score": 12.5,
"risk_level": "HIGH",
"evidence_json": {
"days_inactive": 87,
"last_access": "2025-04-18T10:15:00Z",
"peer_usage_pct": 0.85,
"sensitivity": "CONFIDENTIAL",
"contains_pii": true
},
"recommendation": "REVOKE",
"assigned_to_id": "019f1a2b-3c4d-7000-8000-000000000099",
"workflow_id": "019f7c8d-9ea0-7000-8000-000000007001",
"status": "PENDING",
"due_at": "2025-07-21T23:59:59Z",
"created_at": "2025-07-14T06:30:00Z"
},
{
"id": "019f6b7c-8d9e-7000-8000-000000006002",
"principal_id": "019f1a2b-3c4d-7000-8000-000000000005",
"asset_id": "019f3d4e-5f60-7000-8000-000000000101",
"access_grant_ids": [
"019f2c3d-4e5f-7000-8000-000000000050",
"019f2c3d-4e5f-7000-8000-000000000051"
],
"decay_score": 18.3,
"risk_level": "HIGH",
"evidence_json": {
"days_inactive": 62,
"last_access": "2025-05-13T08:00:00Z",
"peer_usage_pct": 0.92,
"sensitivity": "CONFIDENTIAL",
"contains_pii": true
},
"recommendation": "REVOKE",
"assigned_to_id": "019f1a2b-3c4d-7000-8000-000000000099",
"workflow_id": "019f7c8d-9ea0-7000-8000-000000007002",
"status": "PENDING",
"due_at": "2025-07-21T23:59:59Z",
"created_at": "2025-07-14T06:30:00Z"
}
],
"next_cursor": "eyJpZCI6IjAxOWY2YjdjLThkOWUtNzAwMC04MDAwLTAwMDAwMDAwNjAwMyJ9"
}
Get Review Packet
Retrieve a single review packet by its ID.
Path Parameters
| Parameter |
Type |
Description |
id |
UUID |
The review packet's UUID. |
Example Request
curl -s "http://localhost:8000/v1/reviews/019f6b7c-8d9e-7000-8000-000000006001" \
-H "Authorization: Bearer $TOKEN"
Example Response
{
"id": "019f6b7c-8d9e-7000-8000-000000006001",
"principal_id": "019f1a2b-3c4d-7000-8000-000000000002",
"asset_id": "019f3d4e-5f60-7000-8000-000000000100",
"access_grant_ids": [
"019f2c3d-4e5f-7000-8000-000000000020"
],
"decay_score": 12.5,
"risk_level": "HIGH",
"evidence_json": {
"days_inactive": 87,
"last_access": "2025-04-18T10:15:00Z",
"peer_usage_pct": 0.85,
"sensitivity": "CONFIDENTIAL",
"contains_pii": true
},
"recommendation": "REVOKE",
"assigned_to_id": "019f1a2b-3c4d-7000-8000-000000000099",
"workflow_id": "019f7c8d-9ea0-7000-8000-000000007001",
"status": "PENDING",
"due_at": "2025-07-21T23:59:59Z",
"created_at": "2025-07-14T06:30:00Z"
}
Error Responses
| Status |
Description |
| 404 |
Review packet not found. |
Submit Review Decision
POST /v1/reviews/{id}/decide
Submit a decision on a review packet. Requires the verity.reviewer role.
Idempotency required
The Idempotency-Key header is required for this endpoint. Duplicate submissions with the same key return the original response.
Path Parameters
| Parameter |
Type |
Description |
id |
UUID |
The review packet's UUID. |
| Header |
Required |
Description |
Idempotency-Key |
Yes |
Unique UUID to ensure exactly-once semantics. |
Request Body
| Field |
Type |
Required |
Description |
decision |
enum |
Yes |
CONFIRM · REVOKE · ESCALATE |
justification |
string |
Yes |
Free-text explanation for the decision. |
next_review_at |
datetime |
No |
Schedule the next review (only for CONFIRM). |
escalate_to_id |
UUID |
No |
Reviewer to escalate to (only for ESCALATE). |
Example Request — Revoke
curl -s -X POST "http://localhost:8000/v1/reviews/019f6b7c-8d9e-7000-8000-000000006001/decide" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
-H "Content-Type: application/json" \
-d '{
"decision": "REVOKE",
"justification": "User has not accessed this dataset in 87 days and 85% of peers no longer have this access. Revoking per least-privilege policy."
}'
Example Response
{
"id": "019f8d9e-a0b1-7000-8000-000000008001",
"packet_id": "019f6b7c-8d9e-7000-8000-000000006001",
"decision": "REVOKE",
"decided_at": "2025-07-15T14:22:00Z"
}
Example Request — Confirm with Next Review
curl -s -X POST "http://localhost:8000/v1/reviews/019f6b7c-8d9e-7000-8000-000000006002/decide" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: a3b4c5d6-e7f8-9012-3456-789abcdef012" \
-H "Content-Type: application/json" \
-d '{
"decision": "CONFIRM",
"justification": "User needs quarterly access for SOX audit preparation. Confirmed with data owner.",
"next_review_at": "2025-10-15T00:00:00Z"
}'
Example Response
{
"id": "019f8d9e-a0b1-7000-8000-000000008002",
"packet_id": "019f6b7c-8d9e-7000-8000-000000006002",
"decision": "CONFIRM",
"decided_at": "2025-07-15T14:25:00Z"
}
Example Request — Escalate
curl -s -X POST "http://localhost:8000/v1/reviews/019f6b7c-8d9e-7000-8000-000000006001/decide" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: d4e5f6a7-b8c9-0123-4567-89abcdef0123" \
-H "Content-Type: application/json" \
-d '{
"decision": "ESCALATE",
"justification": "Unable to determine business need. Escalating to CISO for review.",
"escalate_to_id": "019f1a2b-3c4d-7000-8000-000000000080"
}'
Example Response
{
"id": "019f8d9e-a0b1-7000-8000-000000008003",
"packet_id": "019f6b7c-8d9e-7000-8000-000000006001",
"decision": "ESCALATE",
"decided_at": "2025-07-15T14:28:00Z"
}
Error Responses
| Status |
Description |
| 400 |
Invalid request body or decision. |
| 401 |
Missing or invalid Bearer token. |
| 403 |
Caller does not have the verity.reviewer role. |
| 404 |
Review packet not found. |
| 409 |
Decision already submitted (idempotency collision or already decided). |
Reassign Reviewer
POST /v1/reviews/{id}/reassign
Reassign a review packet to a different reviewer. Requires the verity.admin role.
Path Parameters
| Parameter |
Type |
Description |
id |
UUID |
The review packet's UUID. |
Request Body
| Field |
Type |
Required |
Description |
assigned_to_id |
UUID |
Yes |
Verity ID of the new reviewer. |
Example Request
curl -s -X POST "http://localhost:8000/v1/reviews/019f6b7c-8d9e-7000-8000-000000006001/reassign" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"assigned_to_id": "019f1a2b-3c4d-7000-8000-000000000080"
}'
Example Response
{
"id": "019f6b7c-8d9e-7000-8000-000000006001",
"assigned_to_id": "019f1a2b-3c4d-7000-8000-000000000080",
"status": "PENDING"
}
Error Responses
| Status |
Description |
| 400 |
Invalid request body. |
| 403 |
Caller does not have the verity.admin role. |
| 404 |
Review packet not found. |