Build internal tools, integrate with your case-management system, or wire MedLegal data into custom dashboards. Five v1 endpoints, Bearer-token auth, OpenAPI-described, designed for plaintiff law firms with engineering teams.
Generate your API key → Download OpenAPI spec1. Issue a key at /settings/api-keys. Save the raw mlai_… token — it's shown only once.
2. Set Authorization: Bearer mlai_… on every request. 3. Call POST /v1/witness/research:
curl -X POST https://medicalai.law/v1/witness/research \
-H "Authorization: Bearer mlai_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"lastName": "Smith",
"specialty": "cardiology",
"focusArea": "interventional"
}'// Node 18+ — uses native fetch
const res = await fetch('https://medicalai.law/v1/witness/research', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MLAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstName: 'Jane',
lastName: 'Smith',
specialty: 'cardiology',
focusArea: 'interventional',
}),
});
const data = await res.json();
console.log(data.result.publicationCount, 'publications found');import os, requests
r = requests.post(
'https://medicalai.law/v1/witness/research',
headers={
'Authorization': f'Bearer {os.environ["MLAI_API_KEY"]}',
'Content-Type': 'application/json',
},
json={
'firstName': 'Jane',
'lastName': 'Smith',
'specialty': 'cardiology',
'focusArea': 'interventional',
},
)
r.raise_for_status()
data = r.json()
print(data['result']['publicationCount'], 'publications found')Every request to /v1/* (except /v1/openapi.json) must include:
Authorization: Bearer mlai_<32 hex chars>
The key prefix is mlai_. The body is 16 random bytes (hex-encoded). We store only a SHA-256 hash — losing the raw key means rotating it. Keys never expire; rotate manually when staff turn over or when you suspect leakage.
Scopes:
/v1/usage/v1/daubert/memo (consumes Claude tokens; counts toward your hourly quota)Rate limits: Pro tier ships 1,000 calls/hr; Enterprise scales to 10,000+. Every response includes:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 873
X-RateLimit-Reset: 1761403200
On 429, the response body includes the upgrade path. X-RateLimit-Reset is Unix epoch seconds.
/v1/witness/research read9-source expert-witness workup. v1 surfaces PubMed publication history + heuristics; the full 9-source aggregation (NPI registry, Open Payments, NIH RePORTER, Medicare Utilization, SEC EDGAR, state med boards, prior litigation, prior depositions, PubMed) is rolling out endpoint-by-endpoint in v2.
Body:
{
"firstName": "Jane", // optional; combined with lastName
"lastName": "Smith", // required (or `npi`)
"npi": "1234567890", // optional; falls back when name lookup is ambiguous
"specialty": "cardiology",
"focusArea": "interventional" // narrows PubMed term
}
Response:
{
"query": { "firstName": "Jane", "lastName": "Smith", "specialty": "cardiology", "focusArea": "interventional" },
"result": {
"name": "Jane Smith",
"specialty": "cardiology interventional",
"authorTerm": "Smith J[Author]",
"publications": [
{
"pmid": "12345678",
"title": "Outcomes of percutaneous coronary intervention…",
"year": 2024,
"journal": "Journal of the American College of Cardiology",
"authors": ["Smith J", "Lee H", "Park K"],
"firstAuthor": "Smith J",
"url": "https://pubmed.ncbi.nlm.nih.gov/12345678/"
}
// … up to 20
],
"publicationCount": 12,
"topJournals": [{ "journal": "JACC", "count": 5 }],
"topYears": [{ "year": 2024, "count": 3 }],
"observations": [
"12 PubMed publications matched.",
"Active researcher: most recent publication 2024.",
"First author on 4 of 12 papers — leadership role likely."
]
},
"sources": ["pubmed"],
"fetchedAt": "2026-04-25T15:42:01.234Z"
}
/v1/witness/prior-depositions readCourtListener prior-litigation lookup. Returns docket hits + role + judge + a one-line summary per match.
Body: { "name": "Jane Smith MD", "state": "FL" } — npi may be passed instead of name.
/v1/citation/verify readVerify that a legal citation actually supports a claim. Pulls the opinion from CourtListener, asks Claude whether the proposition is supported, returns a verdict + reasoning + opinion URL.
Body:
{
"citation": "123 F.3d 456",
"propositionContext": "A treating physician may give expert opinion testimony without a Rule 26(a)(2)(B) report."
}
Response: { verdict: "supported"|"refuted"|"unsupported"|"opinion_not_found", confidence: 0..1, reasoning: "…", citation, caseName, opinionUrl }
/v1/daubert/memo read-writeGenerate the 14-section Daubert memo as markdown. Uses the same Claude pipeline that powers Courtroom AI's post-depo workup. .docx / PDF rendering is deferred to v2 — for now you receive markdown that you can pipe to your own Word/PDF generator.
Body:
{
"caseContext": {
"witnessName": "Dr. Jane Smith",
"specialty": "cardiology",
"caseCaption": "Doe v. Regional Medical Center"
},
"witnessResearch": { /* the result from /v1/witness/research, optional */ },
"transcript": "Q. Doctor, please state your specialty…\nA. I'm a board-certified cardiologist…\n…"
}
/v1/usage readPer-key call count and remaining quota. Useful for showing usage in your own dashboard.
{
"keyId": "ab12cd34ef56",
"keyHint": "mlai_a1b2…wxyz",
"scope": "read",
"limitPerHour": 1000,
"used": 127,
"remaining": 873,
"resetAt": "2026-04-25T16:00:00.000Z"
}
/v1/openapi.json (public)Full OpenAPI 3.1 spec. Drop into Postman / Bruno / Insomnia / Swagger UI to auto-generate clients.
Outbound webhooks let MedLegal AI push events (session.started, daubert_workup.completed, cite_check.failed, etc.) into your CRM / Filevine / Litify / MyCase / Slack / Zapier without polling. Each request is HMAC-SHA256-signed; receivers verify with their per-hook secret.
Configure at /settings/webhooks.
$249/mo
Custom
| Status | Body | Meaning |
|---|---|---|
| 400 | validation_failed | Required field missing or malformed. |
| 401 | unauthorized / invalid_key | Missing, malformed, revoked, or deleted key. |
| 402 | upgrade_required | API access requires Pro plan. |
| 403 | forbidden | Read-write scope required (Daubert memo). |
| 404 | not_found | Unknown /v1/ path. |
| 429 | rate_limit_exceeded | Per-key hourly quota hit. Body includes upgrade path + reset epoch. |
| 500 | internal | Server-side error. Retry with exponential backoff; if persistent, email support. |
Email [email protected] for general help. [email protected] for SLA / Enterprise quotas / on-prem discussions.