Skip to content

Cases

Cases are compliance work items in the API key's environment, opened by a person or automatically by screening, and usually linked to a transfer. For the case lifecycle, types and categories, see Cases.

Reading needs the cases:read scope; every change, the cases:write scope. The key's owner's role decides the rest:

Action Role permission
List and read cases, notes and history cases:view
Open a case cases:create
Change a case, add a note cases:update
Set or clear the assignee cases:assign
Resolve a case cases:resolve

Linking a transfer, and seeing a case's transfers, also need transfers:read. A key without cases:read that changes a case gets a receipt, { "id", "caseNumber", "status" }, instead of the case.

A role without pii:view (an analyst) gets a case's free text as ***: its title, description and resolution note, its notes, and history values that are not codes or IDs, with meta.piiMasked: true. It searches by case number only. Staff (assignees, authors) are named to everyone who can read cases.

Method Endpoint Scope Description
GET /api/v2/cases cases:read List cases
POST /api/v2/cases cases:write Open a case
GET /api/v2/cases/:id cases:read Get a case
PATCH /api/v2/cases/:id cases:write Change a case
GET /api/v2/cases/:id/notes cases:read List a case's notes
POST /api/v2/cases/:id/notes cases:write Add a note
GET /api/v2/cases/:id/history cases:read List a case's history
POST /api/v2/cases/:id/resolve cases:write Resolve a case

A case of the other environment is 404 CASE_NOT_FOUND.

Terminal window
curl "$COVALENT_URL/api/v2/cases?status=open&assigneeId=me" \
-H "x-api-key: $COVALENT_API_KEY"
Parameter Description
status open or closed.
priority low, medium or high.
type A case type: compliance_review, sanctions_hit, provider_rejection, manual_escalation, threshold_breach or kyc_failure.
assigneeId A member's ID, or me for the key's owner.
search The case number; also the title and description for a role with pii:view. 1 to 100 characters.
hasTransfer true for cases with a linked transfer, false for cases without one.
limit Items per page, 1 to 200, default 50.
cursor meta.cursor of the previous page.

Any other parameter or value is 400 INVALID_QUERY. Cases are listed newest first:

{
"id": "case_id",
"caseNumber": "CASE-00042",
"title": "Review outgoing transfer",
"description": null,
"type": "manual_escalation",
"category": "aml",
"priority": "high",
"status": "open",
"resolution": null,
"resolutionNote": null,
"assigneeId": "user_id",
"assignee": { "id": "user_id", "name": "Jordan Lee", "email": "jordan@example.com" },
"ruleId": null,
"transferIds": ["transfer_id"],
"source": "manual",
"noteCount": 1,
"createdById": "user_id",
"createdAt": "2026-10-09T10:00:00.000Z",
"updatedAt": "2026-10-09T11:00:00.000Z"
}
Terminal window
curl -X POST "$COVALENT_URL/api/v2/cases" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Review outgoing transfer",
"type": "manual_escalation",
"priority": "high",
"transferId": "transfer_id"
}'
Field Required Description
title Yes 1 to 200 characters.
type Yes A case type.
description No At most 2,000 characters.
category No aml, sanctions, kyc, fraud or threshold.
priority No low, medium or high.
transferId No A transfer of the key's environment (422 TRANSFER_NOT_FOUND otherwise).
ruleId No A compliance rule of the key's environment (422 RULE_NOT_FOUND otherwise).
assigneeId No An active member whose role can view cases (422 INVALID_ASSIGNEE otherwise). Needs cases:assign.

No other field is accepted. The answer is 201 with the case in detail (see below). A body that fails validation is 422 VALIDATION_ERROR, with details.issues.

Terminal window
curl "$COVALENT_URL/api/v2/cases/case_id" \
-H "x-api-key: $COVALENT_API_KEY"

The case as listed, plus:

Field Description
resolvedAt, resolvedById When and by whom the case was resolved, or null.
createdBy, resolvedBy Those members, named, or null.
rule The compliance rule that opened the case (id, name, category, action, severity), or null.
transfers The linked transfers (id, externalId, direction, state, complianceStatus, amount, asset, network, createdAt), for a key with transfers:read. transferIds lists them all.
notes, history The 20 latest of each, newest first. The notes and history endpoints page through them all.
historyCount How many history entries the case has.
Terminal window
curl -X PATCH "$COVALENT_URL/api/v2/cases/case_id" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"assigneeId": "user_id",
"priority": "medium"
}'

Send any of title, description, type, category, priority, assigneeId, ruleId and transferId. null clears assigneeId, ruleId or transferId; a new transferId replaces every transfer linked to the case. Setting assigneeId needs cases:assign; any other field, cases:update. The status changes only through resolution.

The answer is the case in detail. A closed case is not changed: 409 CASE_CLOSED. A body with no field is 422 VALIDATION_ERROR.

Terminal window
curl -X POST "$COVALENT_URL/api/v2/cases/case_id/notes" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Called the customer"
}'

content is 1 to 5,000 characters. The answer is 201 with the note: id, content, authorId, author and createdAt. A closed case still takes notes.

GET /api/v2/cases/:id/notes lists a case's notes, newest first, with limit and cursor.

GET /api/v2/cases/:id/history lists a case's history, newest first, with limit and cursor. Each entry has id, action, field, oldValue, newValue, userId, user and createdAt.

Action Meaning
created, updated, assigned, note_added, resolved A change to the case. field, oldValue and newValue say what changed.
transfer_updated Resolving the case moved its held transfer: newValue is the state it reached.
transfer_not_updated Resolving the case could not move its held transfer: newValue is resume_refused or reject_refused.
str_drafted Resolving the case drafted a suspicion report: newValue is the report's ID. Shown only to a key that may read suspicion reports (reports:read and strs:read).
Terminal window
curl -X POST "$COVALENT_URL/api/v2/cases/case_id/resolve" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resolution": "rejected",
"resolutionNote": "Structured payments"
}'
Field Required Description
resolution Yes approved or rejected.
resolutionNote No At most 2,000 characters.

The case is closed, and the answer is the closed case. If its first linked transfer is held, resolving acts on it after the answer: approval resumes the transfer, and rejection rejects it and drafts a suspicion report when the key may (strs:write). meta.transferAction says what happened:

meta.transferAction Meaning
null No linked transfer, or it was not held.
{ "transferId", "result": "queued" } The transfer will be resumed or rejected. The case's history records the outcome.
{ "transferId", "result": "skipped", "reason": "insufficient_permission" } The key may not act on transfers (transfers:write): the transfer stays held.
{ "transferId", "result": "skipped", "reason": "not_rejectable" } Resolved as rejected, but the transfer no longer awaits an officer: it is not rejected, and no report is drafted.

A case that is already closed is 409 CASE_CLOSED. Of two resolutions sent at once, one closes the case and the other gets 409.

A case opened, changed or resolved through the API or the dashboard sends a case.created, case.updated or case.resolved webhook event. Adding a note sends none.