Skip to main content

Cases

A case is a matter tied to a client, identified by a case number: a criminal charge, a citation matter, or any docketed proceeding. Events and payments carry a case_number, so a case groups the records that share it; a message links to a case by its UUID. A case can have several attorneys, one judge, and one location.

This page assumes the shared API Conventions for pagination, filtering, lifecycle actions, and references. All endpoints use the region's base URL and a Bearer token.

Endpoints​

MethodPathDescription
GET/v1/casesList cases
GET/v1/cases/totalCount cases matching filters
GET/v1/cases/{uuid}Get a single case (by UUID or case_number)
GET/v1/cases/{uuid}/attorneysList the attorneys on a case, with when and how each was attached
GET/v1/cases/{uuid}/assignmentsList a case's assignment history
GET/v1/cases/{uuid}/pdfGet a generated PDF of the case
GET/v1/attorneys/{uuid}/casesList the cases an attorney is attached to
DELETE/v1/attorneys/{uuid}Remove an attorney from the agency and from every case of the agency
POST/v1/casesCreate a case
PATCH/v1/cases/{uuid}Update a case
PUT/v1/cases/{uuid}Update a case (alias of PATCH)
POST/v1/cases/assignPreview or run an assignment of attorneys, judges, or locations to many cases
POST/v1/cases/assign/{run}/undoUndo an assignment run
PUT/v1/cases/{uuid}/archiveArchive a case
PUT/v1/cases/{uuid}/restoreRestore an archived or deleted case
DELETE/v1/cases/{uuid}Delete a case (soft delete)

The Case Object​

FieldTypeDescription
uuidstringUnique identifier, generated when the case is created.
clientstringUUID of the client the case belongs to.
case_numberstringThe case number. Required on create.
statusstringAgency-defined case status.
typestringAgency-defined case type.
charge_numberstringCharge number.
codesstringStatute or charge codes.
descriptionstringCase description.
offense_typestringOffense type.
offense_descriptionstringOffense description.
offense_datestringOffense date (YYYY-MM-DD).
arrest_datestringArrest date (YYYY-MM-DD).
arresting_agencystringArresting agency.
arrest_trackingstringArrest tracking number.
file_datestringFiling date (YYYY-MM-DD).
judgment_datestringJudgment date (YYYY-MM-DD).
warrant_statusstringWarrant status for the case.
conditionsstringCase conditions.
victim_namestringVictim name.
offender_namestringOffender name.
locationstringUUID of the location tied to the case.
judgestringUUID of the judge assigned to the case, or null. A case has one judge.
attorneysarrayEvery attorney on the case, oldest link first. On reads, each item is an object with uuid, first_name, last_name, firm_name, and bar_number.
uploadstringUUID of the file import associated with the case, when linked to one.
created_bystringEmail or UUID of the creator.
created_atstringCreation timestamp, UTC.
updated_atstringLast update timestamp, UTC.
archived_atstringSet when the case is archived, otherwise null.
deleted_atstringSet when the case is deleted, otherwise null.

List and single-case responses include attorneys and judge unless slim is set. They also include attorney, the first item of attorneys, for older integrations. attorney is an empty array [] when the case has no attorney. Read attorneys in new integrations, because a case can have more than one attorney.

Primary attorney. attorneys is in attach order: by attach date, then by link row. The first item is the primary attorney of the case. The legacy attorney field is the primary attorney. The attorney merge tags in messages (for example [AttorneyName]) also use the primary attorney. Thus, when an attorney is added as co-counsel, the attorney that a message names does not change. When the primary attorney is removed, the next attorney in attach order becomes the primary attorney.

Create a Case​

POST /v1/cases

Request:

curl -X POST "$BASE_URL/v1/cases" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client": "{client_uuid}",
"case_number": "CASE-2024-001",
"type": "criminal",
"status": "open",
"offense_date": "2024-01-10",
"description": "Traffic violation"
}'

Response (201): the created case.

Create Behavior​

  • case_number: required. A create without one returns 400 with Case number is required.
  • client: attach the case to a client by UUID.
  • attorneys: an optional array of attorney UUIDs (or objects with a uuid) to attach to the case. A comma-separated string is also accepted. Each attorney must be one of the agency's attorneys. Otherwise the API returns 422 with errors.attorneys set to Choose attorneys from this agency's list. and writes nothing. The response includes the attached attorneys as UUIDs.
  • judge: an optional judge UUID. The judge must belong to the agency and must not be archived or trashed. Otherwise the API returns 422 with errors.judge set to Choose a judge from this agency's list.
  • Each attorney, the judge, and the location are written to the case's assignment history with source manual.
  • Creating a case with a client attached triggers a case_created auto message.

List Cases​

GET /v1/cases
curl -X GET "$BASE_URL/v1/cases?client={client_uuid}&status=open&limit=50" \
-H "Authorization: Bearer $TOKEN"

Response (200): a JSON array of case objects.

Query Parameters​

ParameterDescription
searchPartial match on case_number.
case_numberExact match on case number.
clientFilter by client UUID.
statusExact match on status.
typeExact match on type.
charge_numberExact match on charge number.
arresting_agencyExact match on arresting agency.
arrest_trackingExact match on arrest tracking number.
offense_typeExact match on offense type.
arrest_dateExact match on arrest date.
offense_dateExact match on offense date.
file_dateExact match on file date.
judgment_dateExact match on judgment date.
descriptionPartial match on description.
offense_descriptionPartial match on offense description.
offender_namePartial match on offender name.
locationA location UUID. none returns cases with no location, and any returns cases with a location.
judgeA judge UUID, or a comma-separated list of judge UUIDs. none returns cases with no judge, and any returns cases with a judge. A value that names no UUID (and is not none or any) matches no case.
attorneysA comma-separated list of attorney UUIDs: returns cases that have any of them. none returns cases with no attorney, and any returns cases with at least one attorney. A value that names no UUID (and is not none or any) matches no case.
uploadFilter by the file import (upload) UUID that created the cases.
created_byFilter by the creator.

GET /v1/cases/total accepts the same filters.

The attorneys and judge filters read the links in a second database. On some deployments, the API cannot read the links in the same query, so it lists the linked cases first. If that list has more than 50,000 cases, the API refuses the filter with 422. The error is on the filter field:

{
"message": "This attorney filter matches too many cases to run here. Choose a specific attorney, or clear the filter.",
"errors": {
"attorneys": ["This attorney filter matches too many cases to run here. Choose a specific attorney, or clear the filter."]
}
}

For judge, the field is errors.judge and the message is This judge filter matches too many cases to run here. Choose a specific judge, or clear the filter.

Pagination and shaping (limit, skip, sort, sortDirection, fields) follow the shared conventions.

Get a Case​

GET /v1/cases/{uuid}

The path value accepts a case UUID or a case_number. Returns the case with its attorneys, judge, and legacy attorney. Returns 404 with a message of Case {uuid} not found when no case matches.

Update a Case​

PATCH /v1/cases/{uuid}

PUT is an accepted alias. The path value accepts a UUID or a case_number. Send only the fields to change.

curl -X PATCH "$BASE_URL/v1/cases/{case_uuid}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "closed",
"judgment_date": "2024-04-01"
}'

Attorneys, Judge, and Location on Update​

  • attorneys: the full list of attorney UUIDs the case must have. The API applies the list as a difference. An attorney already on the case keeps its link and its attach date. An attorney not yet on the case is added. An attorney missing from the list is removed. An empty array removes every attorney. Omit attorneys to leave the attorneys unchanged. The response includes the attorneys that were sent.
  • Each attorney that the update adds must be one of the agency's attorneys. Attorneys already on the case are not checked. If the check fails, the API returns 422 with errors.attorneys set to Choose attorneys from this agency's list. and writes nothing.
  • judge: a judge UUID sets the judge. "" or null clears it. Omit judge to leave it unchanged. An unknown, archived, or trashed judge returns 422 with errors.judge set to Choose a judge from this agency's list. The judge the case already has is accepted, even when that judge was archived later.
  • location: a change is written to the assignment history as the old location removed and the new location added.

Each change has source manual in the assignment history. To add or remove one attorney without sending the full list, use POST /v1/cases/assign with a cases scope that holds the one case.

Attorneys​

GET /v1/cases/{uuid}/attorneys

Returns every attorney on the case, oldest link first:

[
{
"uuid": "2c3d4e5f-6a7b-4c8d-9e0f-0a1b2c3d4e5f",
"first_name": "Lucia",
"last_name": "Alvarez",
"firm_name": "Alvarez Defense Group",
"bar_number": "IL-6291045",
"email": "lucia@alvarezdefense.com",
"attached_at": "2026-10-06 14:03:11",
"attached_by": "clerk@springfieldcourt.gov",
"source": "bulk"
}
]
  • attached_at: when the attorney was attached, UTC.
  • attached_by: the user who attached the attorney (email, else name, else UUID), or null.
  • source: how the attorney was attached, or null. manual is a case screen, POST /v1/cases, or PATCH /v1/cases/{uuid}. bulk is an assignment run. upload is a file import. undo is an undo that put back a link whose original details were not recorded.

Links made before the assignment history existed have attached_by and source set to null. Their attached_at is the date of the case's last save before that change, so treat it as "on or before" that date.

An Attorney's Cases​

GET /v1/attorneys/{uuid}/cases

Returns the cases the attorney is attached to that are not archived or trashed, newest link first. limit (default 10, at most 100) and skip apply after the API removes archived and trashed cases. Thus each page is full until the list ends. Returns 404 with Attorney {uuid} not found when the attorney does not exist.

[
{
"uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
"case_number": "CR-2025-0117",
"status": "pending",
"type": "criminal",
"client": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"attached_at": "2026-10-06 14:03:11",
"attached_by": "clerk@springfieldcourt.gov",
"source": "manual"
}
]

attached_at, attached_by, and source have the same meaning as on GET /v1/cases/{uuid}/attorneys.

Remove an Attorney from the Agency​

DELETE /v1/attorneys/{uuid}

Attorney records are shared between agencies. This request removes the agency from the attorney's list of agencies. It also removes the attorney from every case of the agency, as one run. Each removal is written to the assignment history of the case with source manual and the run UUID. The request needs the trash_attorneys permission. There is no request that adds the agency back to the attorney.

StatusBodyWhen
204No body.The attorney was not attached to a case of the agency.
200{"message": "Attorney removed from 2 cases", "run": "{run_uuid}", "detached": 2}The attorney was removed from cases. The message says 1 case for one case.
200{"message": "Attorney removed, but not from their cases: remove them from each case.", "run": null, "detached": 0}The attorney was removed from the agency, but the API could not remove the attorney from the cases. Remove the attorney from each case.
404{"message": "Attorney not found"}No attorney matches.

To put the links back, send the run UUID to POST /v1/cases/assign/{run}/undo. The undo restores each link with its original attach date, attached by, and source. The undo does not add the agency back to the attorney.

Assign Cases in Bulk​

POST /v1/cases/assign

Adds or removes attorneys, and sets or clears the judge or location, on many cases in one request. The request runs synchronously and returns 200 with the result. Send "dry_run": true to preview: the API computes the same result and writes nothing. A preview and a run use the same code and the same case query as GET /v1/cases. When the cases do not change in between, the run gets the counts of the preview. The request needs the update_events permission.

Request:

curl -X POST "$BASE_URL/v1/cases/assign" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": { "filters": { "status": "pending", "type": "criminal", "attorneys": "none" } },
"attorneys": {
"mode": "fill",
"uuids": ["2c3d4e5f-6a7b-4c8d-9e0f-0a1b2c3d4e5f", "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a"],
"spread": true,
"max_cases": 150
},
"judge": { "mode": "fill", "uuids": ["4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6071"] },
"notify_attorneys": true,
"dry_run": true
}'

Request Body​

FieldTypeDescription
scopeobjectRequired. Either {"cases": [...]} or {"filters": {...}}, not both.
scope.casesarray1 to 2,000 case UUIDs. Trashed cases are left out. Archived cases are included.
scope.filtersobjectThe query parameters of GET /v1/cases (for example status, type, location, judge, attorneys, archived). The API selects the cases with the same query as GET /v1/cases, with one difference: an assignment never reaches trashed cases. Filters that ask for trashed cases (deleted, else trashed, set to true or deleted) are refused with 422 on scope, for a preview and for a run. Send archived=true to reach archived cases. limit, skip, sort, sortDirection, slim, and fields are ignored.
attorneysobjectOptional. {mode, uuids, spread, max_cases}. Omit it, or send null, to leave attorneys unchanged.
judgeobjectOptional. {mode, uuids, spread, max_cases}. Omit it to leave the judge unchanged.
locationobjectOptional. {mode, uuids, spread, max_cases}. Omit it to leave the location unchanged.
notify_attorneysbooleanDefault false. On a run, email each attorney one list of the cases newly added to them. Ignored on a preview.
dry_runbooleanDefault false. true previews and writes nothing.
sourcestringbulk (default) or manual. Use manual when the request changes one case from a case screen. The value is recorded in the assignment history.
email_reportbooleanDefault true. After a run with source bulk that changes at least one case, email a PDF report to the signed-in user. Ignored on a preview and when source is manual. See Completion Report.

At least one of attorneys, judge, or location is required.

Section Fields​

FieldDescription
modeFor attorneys: add, replace, fill, or remove. For judge and location: replace, fill, or clear.
uuids1 to 50 unique UUIDs of the agency's own records. An attorney must list the agency in its agencies. A judge or location must belong to the agency and must not be archived or trashed. clear takes no UUIDs. remove needs the attorneys to remove, and they do not have to be the agency's own.
spreadDefault false. With true, each case gets one of the chosen records instead of all of them. A judge or location section with two or more UUIDs must set spread to true, because a case has one judge and one location. remove does not accept spread.
max_casesnull or a whole number of 1 or more. Accepted only with spread. A record whose caseload has reached this number is passed over. The caseload is the open cases linked to the record, plus the changes of this run. A case with no candidate left is skipped and counted as at_limit.

Modes​

ModeSectionEffect on each case in scope
addattorneysAdds the chosen attorneys. Attorneys already on the case stay.
replaceattorneysAdds the chosen attorneys and removes every other attorney. A chosen attorney already on the case keeps its link and attach date.
fillattorneysAdds the chosen attorneys only to a case with no attorney. Skips a case that has one.
removeattorneysRemoves the chosen attorneys. Other attorneys stay.
replacejudge, locationSets the chosen value, whatever the case had.
filljudge, locationSets the chosen value only on a case with none.
clearjudge, locationRemoves the value.

Spread and Order​

The API takes the cases in case_number order, then uuid order. With spread, each case gets the candidate with the smallest caseload. The caseload counts only open cases: cases that exist and are neither archived nor trashed. It includes the open cases already linked to the candidate and the changes of this run so far. An archived case in the scope of the run counts for no candidate. A location's caseload is its open cases. A tie goes to the candidate sent first in uuids, so the order of uuids is part of the request. The result is the same for the same request and the same data, so a preview predicts the run.

Limits​

  • A run reaches at most 2,000 cases.
  • A cases scope with more than 2,000 entries returns 422 with errors["scope.cases"] set to Check at most 2,000 cases. This applies to a preview and to a run.
  • A filters scope that matches more than 2,000 cases on a preview returns 200 with over_limit: true and every section count at zero.
  • A filters scope that matches more than 2,000 cases on a run returns 422 with errors.scope.

Response (200)​

A preview and a run return the same shape. This is the response to the request above, sent again with "dry_run": false:

{
"run": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
"dry_run": false,
"cases": 340,
"limit": 2000,
"over_limit": false,
"changed": 262,
"attorneys": {
"mode": "fill",
"cases": 200,
"added": 200,
"removed": 0,
"skipped": { "has_attorney": 0, "at_limit": 140, "already_linked": 0, "not_linked": 0 },
"by_record": [
{ "uuid": "2c3d4e5f-6a7b-4c8d-9e0f-0a1b2c3d4e5f", "added": 110, "removed": 0 },
{ "uuid": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a", "added": 90, "removed": 0 }
]
},
"judge": {
"mode": "fill",
"cases": 90,
"set": 90,
"cleared": 0,
"skipped": { "has_value": 250, "at_limit": 0, "unchanged": 0 },
"by_record": [
{ "uuid": "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6071", "added": 90, "removed": 0 }
]
},
"location": null,
"notified": 2,
"report": "queued"
}

In this example, the two attorneys already had 40 and 60 open cases. The cap of 150 let them take 110 and 90 more, and the other 140 cases were skipped as at_limit.

FieldDescription
runThe UUID of the run. Pass it to the undo endpoint. null on a preview.
dry_runtrue for a preview.
casesThe number of cases in scope.
limitThe most cases a run can reach (2000).
over_limittrue when cases is more than limit.
changedThe number of cases where at least one thing changed.
attorneys, judge, locationWhat each section did, or null when the request did not include it.
notifiedThe number of attorney emails accepted. Always 0 on a preview.
reportqueued when the API queued the completion report, failed when it could not queue the report, or null when no report was due.

Each section has mode, cases, and by_record. cases is the number of cases that the section changed. by_record lists each chosen UUID in request order, with the number of cases that gained it (added) or lost it (removed). The attorneys section counts links in added and removed. Attorneys that replace removes are counted in removed, and they are not listed in by_record unless they were also chosen. The judge and location sections count cases in set and cleared.

Skipped countMeaning
has_attorneyfill: the case already had an attorney.
already_linkedadd or replace: the chosen attorney was already on the case. A case where every chosen attorney already was is not counted in changed.
not_linkedremove: the attorney was not on the case.
has_valuefill: the case already had a judge or location.
unchangedreplace: the case already had that judge or location.
at_limitspread with max_cases: every candidate had reached the cap.

Attorney Email​

When notify_attorneys is true on a run, the API sends an email to each attorney that got new cases. An attorney with no valid email is skipped. Each attorney gets one email for the run, not one email per case. The subject is the agency setting attorney_notification_subject, or Cases Assigned when that setting is blank. The sender is attorney_notification_from_email when it is a valid email. The body says how many cases were assigned, then lists the case number, status, type, and description of each.

The API sends the emails after it saves the run. If the emails fail, the run stays saved and the response is still 200 with the run UUID, so the run can be undone. notified counts only the emails that were accepted.

Completion Report​

After a run, the API queues a PDF report for the signed-in user when all of these are true:

  • dry_run is false and source is bulk.
  • email_report is true or not sent.
  • changed is more than 0.
  • The signed-in user has an email address.

A worker builds the PDF and emails it to that address only. The subject is Case Assignment Complete: N cases changed. The PDF lists who ran the run and when, the scope and its filters, the request, the totals and skipped counts, the changes for each attorney, judge, and location, and every changed case. For each changed case, it shows the attorneys added and removed, and the judge and location before and after.

report in the response is queued when the job was queued and null when no report was due. It is failed when the API could not queue the job. A failed report does not fail the request: the run stays saved and the response is still 200. A change to one case with source manual, and the removal of an attorney from the agency, never send a report.

Errors​

A request that fails validation returns 422. message holds the first problem, and errors holds every problem by field path:

{
"message": "Choose at least one attorney, judge or location to assign.",
"errors": {
"assign": ["Choose at least one attorney, judge or location to assign."]
}
}
{
"message": "This reaches 4,210 cases. A run can change at most 2,000: narrow the filters or check the cases to assign.",
"errors": {
"scope": ["This reaches 4,210 cases. A run can change at most 2,000: narrow the filters or check the cases to assign."]
}
}
{
"message": "Assignments do not apply to trashed cases.",
"errors": {
"scope": ["Assignments do not apply to trashed cases."]
}
}
Field pathMessage
scopeChoose the cases to assign: check them in the list, or send the filters the list is showing. or Assignments do not apply to trashed cases. (the filters ask for trashed cases).
scope.casesCheck at least one case to assign., Check at most 2,000 cases., or Each checked case must be a case uuid.
scope.filtersSend the filters as the cases list sends them to GET /cases.
scope.filters.attorneys, scope.filters.judgeThis attorney filter matches too many cases to run here. Choose a specific attorney, or clear the filter. or This judge filter matches too many cases to run here. Choose a specific judge, or clear the filter. The API could not list the linked cases for the filter (more than 50,000).
attorneys.modeChoose how to assign attorneys: add, replace, fill or remove.
judge.mode, location.modeChoose how to assign the judge: replace, fill or clear. (or the location)
{section}.uuidsChoose at least one attorney., Choose each attorney once., Choose at most 50 attorneys., or Choose attorneys from this agency's list. (with the noun of the section)
{section}.uuids1 chosen attorney is not in this agency's list. or 2 chosen judges are archived or not in this agency's list.
judge.spread, location.spreadA case has one judge: to assign several, spread the cases across them.
attorneys.spreadSpread applies when assigning attorneys, not when removing them.
{section}.max_casesThe most cases must be a whole number of 1 or more. or Set the most cases only when spreading the cases across the attorneys.
attorneys, judge, locationSend attorneys as an object with a mode and uuids. (with the noun of the section)
notify_attorneys, dry_run, email_report, {section}.spreadNotify attorneys must be true or false., Dry run must be true or false., Email report must be true or false., or Spread must be true or false.
sourceSource must be bulk or manual.

An unexpected failure returns 500 with The assignment could not be saved. Try again.

Earlier Request Body​

Before October 2026, this endpoint queued a background job and returned 202. That job no longer exists. The API still accepts the earlier body: a body with no scope and with attorney, judge, or location as a string. The API maps it to the current shape and runs it at once (it never previews):

  • The scope is the cases that match type and status.
  • A UUID becomes replace with that one record.
  • random becomes replace over all of the agency's records with spread: true, and max_per_attorney, max_per_judge, or max_per_location becomes max_cases. A blank, zero, or negative value means no cap.
  • A blank value leaves that section unchanged.
  • notify_attorney becomes notify_attorneys.

The 2,000 case limit applies. The response is the 200 result above. New integrations must send the current shape.

Undo an Assignment Run​

POST /v1/cases/assign/{run}/undo

Reverses one run. {run} is the run UUID from the assign response. The API reads the changes of that run, newest first, and reverses a change only when the case still holds what the run left:

  • An attorney the run added is removed, if it is still on the case.
  • An attorney the run removed is put back, if it is not on the case now. The link gets its original attach date, attached by, and source when those were recorded.
  • A judge or location that the run set goes back to the previous value. This occurs only if the case still holds the value that the run set.

A change the case no longer holds is left as it is and counted in kept. The reversals are written to the assignment history with source undo and a new run UUID. The request needs the update_events permission.

Request body (optional):

{ "email_report": true }

email_report defaults to true. A value that is not a boolean returns 422 with errors.email_report set to Email report must be true or false. The API queues a PDF report of the undo for the signed-in user only when email_report is true, the undo reversed at least one change, and the undone run was a bulk run. The subject is Case Assignment Undone: N changes reversed. An undo of a manual change or of an attorney removal never sends a report.

Response (200):

{
"run": "6a7b8c9d-0e1f-4a2b-9c3d-4e5f6a7b8c9d",
"undone": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
"reversed": 180,
"kept": 4,
"report": "queued"
}

report has the same values as on POST /v1/cases/assign: queued, failed, or null.

Returns 404 with Assignment run {run} not found when the agency has no changes for that run. A second undo of the same run reverses nothing, and the counts show that.

Assignment History​

GET /v1/cases/{uuid}/assignments

Returns every change to the attorneys, judge, and location of a case, newest first. limit defaults to 50, with a maximum of 100. skip pages through older changes. Changes come from case saves, assignment runs, file imports, and undos. The request needs the view_any_event permission.

[
{
"id": 991,
"kind": "attorney",
"record": "2c3d4e5f-6a7b-4c8d-9e0f-0a1b2c3d4e5f",
"name": "Lucia Alvarez (Alvarez Defense Group)",
"action": "added",
"source": "bulk",
"run": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
"created_by": "clerk@springfieldcourt.gov",
"created_at": "2026-10-06 14:03:11"
}
]
FieldDescription
kindattorney, judge, or location.
recordThe UUID of the attorney, judge, or location.
nameThe record's name. An attorney reads as first and last name with the firm in parentheses, else the firm, else the bar number. null when the record no longer exists.
actionadded or removed.
sourcemanual, bulk, upload, or undo.
runThe run UUID for a change made by an assignment run or an undo. null for a single change.
created_byThe user who made the change (email, else name, else UUID), or null.
created_atWhen the change was made, UTC.

Archive, Restore, and Delete​

PUT /v1/cases/{uuid}/archive
PUT /v1/cases/{uuid}/restore
DELETE /v1/cases/{uuid}
  • Archive sets archived_at and removes the case from default lists. Returns {"message": "Case archived"}, or 404 with Case not found.
  • Delete is a soft delete: it sets deleted_at. Returns a 204 with no body.
  • Restore clears archived_at and deleted_at. Returns {"message": "Case restored"}, or 404 with Case not found.

The agency setting Auto Delete Trashed Data deletes trashed cases permanently after its retention period. When a case is deleted this way, its attorney links, its judge, and its assignment history are deleted with it.

FAQs​

How does a case relate to events, payments, and messages?

Events and payments carry a case_number, and the case groups the records that share it. Set the same case_number on an event or payment as on the case to associate them, and filter events or payments by case_number. A message links to a case by its UUID through the message case field, so filter messages with ?case={case_uuid} rather than by case number.

How do I attach a case to a client?

Set the client field to the client's UUID on create. A case with a client attached also triggers a case_created auto message.

How do I look up a case by its case number?

Pass the case number in the path of a get or update (GET /v1/cases/CASE-2024-001), or filter the list with GET /v1/cases?case_number=CASE-2024-001. Use search for a partial match.

How do I assign an attorney to a case?

Send POST /v1/cases/assign with "scope": {"cases": ["{case_uuid}"]} and "attorneys": {"mode": "add", "uuids": ["{attorney_uuid}"]}. Use "mode": "remove" to take the attorney off. This changes only that attorney. An attorneys array on create or update also works. On update, the array sets the full list, so an attorney not in the array is removed. Read the result with GET /v1/cases/{uuid}/attorneys.

How do I preview a bulk assignment before it runs?

Send the same body with "dry_run": true. The response has the same counts the run would produce and run is null. Send the body again with "dry_run": false to run it.

How do I find cases with no attorney or no judge?

Filter with attorneys=none or judge=none on GET /v1/cases or GET /v1/cases/total. Use location=none for cases with no location. The same filters work in the filters scope of an assignment.

Why did creating a case return a 400?

case_number is required. A create without it returns 400 with Case number is required.

  • API Conventions: shared listing, filtering, and lifecycle behavior
  • Clients: the person a case belongs to
  • Events: hearings and dates that share a case number
  • Payments: balances that share a case number
  • Error Handling: status codes and error responses