Discovery for legal cases
Keep, search, tag and export the mail a legal matter needs: cases, the people they name, holds that keep mail whoever deletes it, every opening logged, and exports sealed under a passphrase.
When a legal matter needs an organisation’s mail, discovery keeps it, finds it and hands it over: the mail of the people the matter names, from the days it covers, about what it is about, kept whoever deletes it, and exported in one sealed file.
A case is one matter. It names:
- its people (custodians): whose mail it is about. Name a person, somebody who has left, or a group, whose members are each added;
- its holds: which of their mail is kept, by dates and by a query, for example
from:acme.example after:2026-01-31; - its sets: what a search found, kept as a set so it can be reviewed and exported;
- its tags: a reviewer’s judgment of each message a set holds: responsive, privileged or not responsive;
- its log: everything done in it, by whom and when.
Mail a hold matches is kept until the hold is lifted or the case is closed, even when its owner deletes it, it is purged, or a retention policy would delete it; kept mail is out of its owner’s sight. A hold covers mail that arrives later too. A person named in an open case is never removed from the organisation, so their mail can’t go with them.
Who may
Discovery is the auditor’s. The organisation’s administrators do not have it, so nobody who manages the people can also read their mail for a case. An organisation can also put the right into a custom role, such as a legal team’s, but only once a second administrator approves. The server’s operator can see that cases exist and nothing else.
Releasing what a case keeps, by closing the case, removing one of its holds or taking a person out of it, waits for a second administrator when the organisation requires approval for lifting a legal hold.
In the console
Records › Cases lists the cases, open and closed. Open one to see its people and holds, with tabs for the rest:
- Search: a query and dates over everybody in the case, or the people you leave ticked. The answer shows how many messages each person has, then the messages a page at a time, each with Open. Keep as a set names what was found and keeps it.
- Sets: each set with how many messages it holds and who kept it when. Open a set to list its messages; opening a message shows its headers and its source, read-only, and is written to the log. Each message has a button for each tag, and Untag; its tag shows beside it.
- Exports: Export on a set asks for the passphrase twice and shows how strong it is, how the messages are written (One file a message (EML) or One mailbox file (MBOX)), and which go (every message of the set, or only those with one tag). The console never keeps it, in the page or the browser. The export shows Being made, then Ready with its size and the day it is deleted; Download saves the sealed file.
- Log: everything done in the case, oldest first.
Records › Cases is shown to auditors, and to people whose custom role holds the discovery right.
Opening a case and keeping mail
vsx admin case add "Supplier dispute 2026"
vsx admin case people 3 ada@example.com bo@example.com
vsx admin case hold 3 --from 2026-01-01 --until 2026-06-30 --query 'from:acme.example'
vsx admin case show 3
A hold with no query keeps everything of its people in its dates. A case can have several holds; mail any of them matches is kept.
Writing a query
The words are joined by AND; a leading - turns a word round, and a value with spaces is quoted.
| Word | Matches |
|---|---|
from: to: cc: bcc: subject: body: | That field holds the text. |
text: or a bare word | Any of those six holds it. |
has:attachment | It has an attachment. |
larger: smaller: | Its size in bytes. |
after: before: on: | The day it arrived, YYYY-MM-DD, UTC. |
For example: from:acme.example subject:"price list" after:2026-01-31 -has:attachment.
Searching and keeping what you find
A search runs one query over every person of the case, or only those you name, including mail they deleted that a hold kept. It says how many messages each person has, then lists them a page at a time.
vsx admin case search 3 --query 'subject:"price list"'
vsx admin case search 3 --query 'subject:"price list"' --people ada@example.com,bo@example.com
vsx admin case set 3 "Price lists" --query 'subject:"price list"'
vsx admin case sets 3
vsx admin case show-set 3 1
A set keeps up to 10,000 messages, and a case up to 100 sets.
Tagging what you found
Reviewing a set means saying of each message whether it answers what the case asks. A message is tagged responsive, privileged (kept back from what is handed over) or not-responsive. Only messages one of the case’s sets holds can be tagged, up to 1,000 at once; each change is written to the case’s log, with who made it and how many messages it changed.
Name messages as show-set lists them, by account and message number:
vsx admin case show-set 3 1
vsx admin case tag 3 7/4182 7/4190 --as responsive
vsx admin case tag 3 9/221 --as privileged
vsx admin case untag 3 7/4190
vsx admin case tags 3
Tagging a message that already has another tag changes it.
Opening a message
vsx admin case open 3 ada@example.com 4182 --out message.eml
Every opening is written to the case’s log and the audit log before the message is read. A message outside the case answers as not found.
Exporting
An export is a set, sealed in one file: each message as an .eml file in a zip, with a manifest.csv saying whose mailbox each came from and its SHA-256, all encrypted under a passphrase you choose. Written as MBOX instead, the zip holds one messages.mbox, which most mail apps and review tools import, and the manifest names each message’s place in it. The passphrase is not kept anywhere, so the file is useless to anyone without it, the server included.
vsx admin case export 3 1
vsx admin case export 3 1 --format mbox --tag responsive
vsx admin case exports 3
vsx admin case show-export 3 1
vsx admin case download 3 1 --out supplier-dispute.sealed
--tag exports only the set’s messages with that tag; without it, every message of the set goes. case export asks for the passphrase without showing it, or reads it from standard input with --secret-stdin. The export is made in the background; show-export says when it is ready. It is kept for seven days and then deleted. Downloading it is logged.
Whoever receives the file opens it with the server’s own binary, anywhere, with no configuration and no server:
versealx-server case open supplier-dispute.sealed --out supplier-dispute.zip
It asks for the passphrase, or reads it with --password-stdin. A file that has been changed, or the wrong passphrase, opens nothing and leaves nothing behind.
Closing a case
vsx admin case lift 3 2
vsx admin case close 3
vsx admin case log 3
Closing a case lifts its holds: what they kept is deleted again by whatever would have deleted it. The case and its log stay, read-only.
Over the API
| Method | Path | Purpose |
|---|---|---|
GET, POST | /api/v1/tenants/{tenant}/cases | The cases; open one with name. |
GET, PATCH | /api/v1/tenants/{tenant}/cases/{id} | One case; rename it, or close it with {"open": false}. |
POST | /api/v1/tenants/{tenant}/cases/{id}/custodians | Add people, by addresses. |
DELETE | /api/v1/tenants/{tenant}/cases/{id}/custodians/{account} | Take a person out. |
POST | /api/v1/tenants/{tenant}/cases/{id}/holds | Set a hold: from, until and query, each optional. |
DELETE | /api/v1/tenants/{tenant}/cases/{id}/holds/{hold} | Lift a hold. |
POST | /api/v1/tenants/{tenant}/cases/{id}/search | Search: query, from, until, people (addresses; all of the case’s when absent), position, limit. |
GET, POST | /api/v1/tenants/{tenant}/cases/{id}/sets | The sets; keep one with name, and query, from and until as a search takes them. |
GET | /api/v1/tenants/{tenant}/cases/{id}/sets/{set} | One set’s messages. |
GET | /api/v1/tenants/{tenant}/cases/{id}/messages/{account}/{message} | Open one message, logged. |
GET, POST | /api/v1/tenants/{tenant}/cases/{id}/tags | The tags, each account, message and tag; tag messages with messages (each account and message) and tag, or null to take it off. |
GET, POST | /api/v1/tenants/{tenant}/cases/{id}/exports | The exports; start one with set and passphrase, and optionally format (eml or mbox) and tag. |
GET | /api/v1/tenants/{tenant}/cases/{id}/exports/{export} | One export’s state. |
GET | /api/v1/tenants/{tenant}/cases/{id}/exports/{export}/download | The sealed file, logged. |
GET | /api/v1/tenants/{tenant}/cases/{id}/log | The case’s log. |
Something unclear or out of date on this page? Tell us.