Plugs into what you already run, with nothing in between you cannot audit.
Records come in through connectors your firm can read, from databases, web APIs, files and spreadsheets, and are checked against official registers. They go out through a published API, a change feed, webhooks and scheduled pushes, each saying who is asking and where every value came from. AI agents ask the same way, through the same checks.
A connector is a settings file, and nothing is written until a rehearsal has run.
A connector written as software becomes software your firm has to maintain. A connector written as a settings file is a document your firm can read, compare and approve. An implementation consultant, not a platform engineer, builds one in days.
Describe
The settings file: which system, which fields, how to tidy each one, and what it is.
Validate
Check it makes sense. Every field is either mapped or deliberately ignored; nothing is silently dropped.
Rehearse
Run it against real data and write nothing. It shows what would change. A connector that has never been rehearsed cannot write.
Run
In pieces, resumable. Retries, failures queued, and a record of the run kept.
What a settings file can point at
Databases
SQL Server, PostgreSQL and Oracle, read as a table or a query. Always a replica or a nightly restored copy, never the live production database, because that is the access a practice management vendor will actually grant.
Web APIs
REST endpoints, signing in with basic credentials, OAuth 2.0 or an API key. The shipped CRM connector reads one, picking up from the last change it saw.
Files
A file share or an SFTP drop. The same settings file, the same rehearsal, the same record of the run.
Spreadsheets
A guided import: upload, detect, map, check, preview, commit. Mapping templates are reused. The file's checksum is shown, so the commit provably reads what was previewed. A sheet can go out to Excel and come back with each row keyed.
Supplied for every connector, so nobody writes it twice
Only what changed
An incremental load reads from a watermark with an overlap window. The watermark advances from the data rather than the clock, so a source with a slow clock loses nothing. Rows whose content has not changed are recognised and skipped.
Loaded once, whatever happens
A record that arrives twice is stored once. That is enforced by a database constraint, not by the connector remembering to check.
Drift is caught, not absorbed
If a source column disappears or changes type, the load is quarantined and nothing is applied. A half-applied load is the one no re-run can reproduce.
Rejects come with reasons
A record that cannot be conformed is listed with what was wrong with it. The rehearsal reports coverage three ways. A wrong mapping, a required field that is empty in reality, and a column nobody looked at each show up as themselves.
Secrets never sit in the file
A credential is a reference to the firm's vault. A password typed into a settings file is refused before it can reach version control or the audit trail.
Tidy-ups are named, not coded
Fourteen named transformations: trim, upper, dates to ISO, digits only and their kind. An escape hatch into code exists for what they cannot express, and every use is flagged for review and counted.
Working examples included
Elite 3E comes as a working connector: five streams over the client, matter, timekeeper and organisational unit tables. The client table is read twice, because the client relationship and the organisation behind it are different things. A generic CRM connector shows the same shape over a web API.
An agent can draft one
A separate set of twelve tools lets an AI assistant explore a source, profile its columns by pattern rather than value, and draft the settings file. It can rehearse the file and run the contract tests. That assistant is kept apart from mastered data by the code's own import structure, so a connector-authoring agent can never read a client record.
Loads that survive a bad night
Work is done in pieces, with save points and retries. A load that fails at three in the morning picks up where it stopped. Anything it could not process is queued for a person, and the whole run can be replayed.
"Verified" means a date and a source, not a tick in a box.
Every check against Companies House, CIPC or OpenCorporates is kept on file: what was checked, against which authority, when, and what came back. Re-verification is scheduled, and a registration number that stopped matching last month becomes a data quality problem to deal with, not a value that quietly goes stale.
Companies House
United Kingdom. Legal names, registration numbers and registered offices, with the date each was confirmed.
CIPC
South Africa. The Companies and Intellectual Property Commission register, checked the same way.
OpenCorporates
Multi-jurisdiction. Used where a national register has no usable interface, and recorded as the source it is.
A register's answer arrives as a proposal. If the register disagrees with the record, the difference goes to a person to decide. Nothing is written on the register's say-so.
Six ways in, and each says who is asking.
Looking up "which client is this, really?" is the busiest request, and the one that makes Datum useful to every other system in the firm. Nineteen times in twenty it answers in under 200 ms, measured on our test set.
| Route | What it answers |
|---|---|
GET /v1/xref/{system}/{key} | Turn one system's reference into the master one |
GET /v1/records/{master_id} | The full record, as at any date you choose |
GET /v1/search | Search, with permissions applied as it runs |
GET /v1/changes | What has changed, for systems keeping in step |
GET /v1/extracts/{entity} | Bulk extracts, saying which columns were withheld |
GET /v1/schema | The data model, filtered to what you may see |
Looking up a client: the request
GET /v1/xref/elite3e/LON000412 Authorization: Bearer ••••••
Response
{
"master_id": "01936f2a-…",
"entity": "party_organisation",
"attributes": {
"legal_name": "Pemberton Holdings Ltd",
"country": "GB"
},
"provenance": {
"legal_name": {
"source": "elite3e", "record": "LON000412",
"rule": "highest_trust", "pinned": false,
"selected_at": "2026-08-24T02:14:07+00:00"
}
},
"as_at": "2026-08-24T09:00:00+00:00",
"contract_version": "1.0"
} Saying where a value came from is not optional
Every field, on every response. Without it, the system reading has no way to judge how far to trust a value. Datum refuses to send a response that is missing it.
"Not found" does not mean it is not there
It means it is not available to you. A matter that does not exist and a matter behind an ethical wall look exactly the same, because telling them apart would give the game away.
Totals are the totals you may see
Every list carries suppressed and complete. If complete is false, that total is not the firm's total, and no system should present it as one.
Three questions about time
A record can be read three ways: as at the moment permissions are judged, as at when a fact was true in the world, or as at when the firm believed it. Who was the client in March, and what did we know in March, are different questions. They are the pair a professional indemnity claim needs years later. A store that cannot answer one says so rather than handing back today's values.
Merges never strand a reader
Identifiers are never reused. After a merge, asking for the retired one returns the surviving record with a note naming what you asked for. A system holding an old reference is told where to point it.
Errors are structured and stable
Every failure is a machine-readable problem report with a code that does not change between versions. "Erased" is a distinct answer from "never existed", because a system holding a copy needs to be told to erase its own.
Contracts carry their dates
Ten contracts are published in all, from the cross-reference lookup and the change feed to the write path with change requests, jobs, lineage and notifications. A consuming system reads the list and sees each one's introduction, deprecation and sunset dates, rather than discovering a change when something breaks.
One permission never implies another. An administrative permission does not grant a read permission. Every system that connects gets its own credentials, including the AI integration. A role can also withhold particular fields, and a withheld field is named in the response, never silently left blank.
Other systems keep in step without a copy of the wall.
Four ways to keep a downstream system current, from a feed it reads to a push Datum makes. Every one is screened for the identity that receives it, at the moment it receives it.
The change feed
A numbered sequence of everything that changed, with no gaps and one order for the whole firm. Delivery is at least once, with a key to drop duplicates on. A cursor that has expired is refused with a pointer to re-baseline from a bulk extract, never skipped over quietly. Thirty days are kept by default.
Permissions are applied when an event is read, not when it was written. A wall raised this morning hides an event from last week for the people it screens. The same event is visible to one consumer and not another, and that is correct.
Webhooks
Datum calls your endpoint when something you subscribed to changes. A subscription names the identity it delivers as and receives only what that identity may see, because a delivery has no person behind it to check against. Endpoints must be HTTPS, subscriptions filter by event and by entity, and every delivery attempt is recorded.
Scheduled push
For a system that cannot reach in, and a firm's own data centre is exactly that, Datum initiates the connection outbound on the firm's schedule. The firm can see what left and can stop it leaving without the other side's cooperation. Rows whose content has not changed are not sent again. A batch that fails marks the run partial and is re-sent next cycle, and nothing is sent at all without a credential.
Where the receiving system already holds a different value, the difference is recorded and shown, not overwritten. The resolution belongs to a person.
Bulk extract and search
An extract is built by the same permission check as every other read; there is no separate export query where the wall could be forgotten. It reports how many rows and which columns were withheld. Search, over legal-aware analysers, applies permissions inside the query, so facets and counts are over what the caller may see. It is fed from the same change stream as everything else.
Every value says where it came from, and every source column says what it feeds.
Provenance is on every response. Lineage is recorded on every run, in the open OpenLineage format, and published through the API and the stewardship screens. With the model, the code lists and the taxonomy, it answers what a data team asks a catalogue: what exists, what it means, who may see it, and where it came from.
Provenance, on every field
Which source, which record, which rule chose it, whether a person pinned it, and when. Four kinds of origin are kept apart: a source system, an external register, a steward's assertion, and an inference from matching. They are never presented as the same kind of claim.
Lineage, on every run
Each of the six stages (extract, standardise, conform, match, survive, publish) records an event in the OpenLineage format, the open standard lineage tools read. The stages that produce values also record which source column fed which golden field. Recording is not optional and cannot be switched off, because lineage that is off by default is off in production.
The API answers "where did this value come from?" for any field of any record, permissions applied, as a chain a person can read: source column, transformation, golden field. The stewardship application shows the same chain beside the value. A chain that is incomplete is reported as a connector defect, not shown as "unknown".
Impact, before a change
The same record answers the reverse question: which golden fields does this source column feed? It is the question a data lead has before a practice management upgrade retires a column, and without it that change is made blind.
The model, as a document
The data model is published as a JSON Schema, with every field annotated: how sensitive it is, its role in matching, whether it is derived, and its SALI classification. Each entity says whether it is mastered and what its natural key is, the two things a data architect looks for first. It is filtered to what the caller may read, and names what was withheld. The stewardship application's own model diagram is drawn from it.
Code lists and the taxonomy
Reference data is a catalogue of code lists with a mapping from each source system's codes onto the firm's canonical ones. Unmapped codes queue for a person, every value shows where it is used, and a code still in use cannot be retired. The SALI Legal Matter Standard Specification is the taxonomy spine, with the firm's own extensions in their own namespace and crosswalks to what the firm already uses.
Bring your own catalogue
Datum ships no separate catalogue product. A firm running its own catalogue or lineage store points it at these endpoints and forwards the OpenLineage events unchanged; Marquez is the one they are shaped for. No third-party component's own screens are ever shown to a firm's users, because none of them knows what an ethical wall is.
Seven questions an agent can ask, and one thing it can propose.
An AI agent asks through the Model Context Protocol (MCP), the open standard AI tools use to call other systems. It reads with its own identity, through the same checks as a person, and gets the same record with the same source attached. The only write is a proposal into the review queue. Any agent that speaks the protocol can be pointed at it; Trovato is the first.
| Tool | The question it answers |
|---|---|
get_entity | Look up a record |
search_entities | Search, with permissions applied as it runs |
resolve_entity | Which client is this, really? |
classify | Classify this piece of work |
get_matter_context | Everything about a matter, as at a date |
get_corporate_group | The corporate group a company belongs to |
propose_contribution | Propose something new, into the review queue |
POST /mcp Authorization: Bearer •••••• (trovato-agent · mdm:read) { "jsonrpc": "2.0", "id": 41, "method": "tools/call", "params": { "name": "get_matter_context", "arguments": { "matter_number": "24-0417", "as_at": "2026-03-14" } } }
{
"result": {
"matter_number": "24-0417",
"client": "Pemberton Holdings Limited",
"jurisdiction": "England and Wales",
"classification": "Corporate — Mergers & acquisitions",
"restricted": false,
"parties": [
{ "name": "Pemberton Holdings Limited", "role": "client" },
{ "name": "Cavendish Technologies Ltd", "role": "counterparty" }
],
"personnel": [
{ "name": "A. Wainwright", "role": "responsible partner",
"from": "2024-02-12", "to": null }
],
"provenance": {
"client": { "source": "companies_house", "selected_at": "2026-08-14T02:14:07Z" },
"jurisdiction": { "source": "elite3e", "selected_at": "2026-08-24T02:14:07Z" }
}
}
} A matter behind a wall and a matter that does not exist get the same reply, byte for byte. The transport cannot tell the agent the difference either.
{"result":{"isError":true,"content":[{"type":"text","text":"not found"}]}} Live in Trovato.
trovato.ai · legal operations platform · lawyers run matters with supervised AI agentsIntake, already filled
When a lawyer opens a matter in Trovato, the client, the parties and the governing jurisdiction come from Datum. Nobody retypes them, so nothing is mistyped. Retyping is where wrong data enters.
Agents ask back
Trovato's Matter Agents ask Datum for matter context as they work, with their own credentials. Every field comes back with its source, which is what Trovato's Citation Firewall needs before an answer can ship.
Findings return as proposals
What an agent learns from a document goes into Datum's review queue as a suggestion. A reviewer decides. The record never changes on an agent's say-so.
Datum pushes. Trovato never reaches into your network. The firm owns the schedule, can see what left, and can stop it leaving without asking anyone.
Two identities, screened differently. A directory identity publishes the list of matters, with walled ones marked restricted. A detail identity publishes matter content and is screened by every wall. A walled matter's name crosses; its content never does. Nothing that could be read as a clearance ever leaves.
Switch it off and the route does not exist.
Not disabled, absent. With the integration off there is no agent route in the software at all. The whole platform builds and passes every test that way, and proving it is one of the eight checks that block a release.
Runs wherever your firm needs it to run.
In your own data centre, or as a managed single instance. Neither is a lesser product.
In your own data centre, without a lesser product
The typefaces are served by Datum itself, and no screen fetches anything from an outside company. A machine inside your network has no route out, and the product does not quietly fall back to Arial.
A database doing real work
PostgreSQL 16, ninety-one tables. The rules that stop two conflicting versions of the same thing existing at once are enforced by the database itself, not by application code a simultaneous write can slip past.
Joins, not rebuilds
Scheduling, loading, transforming, search, sign-in, permissions, lineage, events, graph traversal and matching at scale are each a named seam with a working default behind it. Datum runs without any of them and gains from each your technology team already operates.
AirflowdltdbtOpenSearchKeycloakOpenFGAMarquezNATSApache AGESplink
Two AI connections, deliberately kept apart
One for the people building Datum and one for the running product, so a convenience for developers can never reach live data. A firm that wants no AI model near its client data runs Datum without one and loses nothing else.
Bring your systems to the walkthrough.
Tell us your practice management system in the form and we will have the right connector open. We will show the settings file, the rehearsal run, the feed another system reads, and the chain from a source column to a golden value.
Questions before booking? Use the contact form.