MedLegal AI Developer Portal

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 spec

Quickstart

1. 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
Node.js
Python
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')

Authentication

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:

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.

Endpoints

POST/v1/witness/research read

9-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"
}

POST/v1/witness/prior-depositions read

CourtListener 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.

POST/v1/citation/verify read

Verify 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 }

POST/v1/daubert/memo read-write

Generate 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…"
}

GET/v1/usage read

Per-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"
}

GET/v1/openapi.json (public)

Full OpenAPI 3.1 spec. Drop into Postman / Bruno / Insomnia / Swagger UI to auto-generate clients.

Webhooks

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.

Pricing

Pro

$249/mo

  • 1,000 API calls/hour
  • Up to 10 active keys
  • All five v1 endpoints
  • Webhooks (10 endpoints)
Upgrade →

Enterprise

Custom

  • 10,000+ calls/hour (configurable)
  • Unlimited keys
  • Dedicated rate-limit pool
  • Priority support + Slack channel
  • SLA + BAA
Contact sales →

Errors

StatusBodyMeaning
400validation_failedRequired field missing or malformed.
401unauthorized / invalid_keyMissing, malformed, revoked, or deleted key.
402upgrade_requiredAPI access requires Pro plan.
403forbiddenRead-write scope required (Daubert memo).
404not_foundUnknown /v1/ path.
429rate_limit_exceededPer-key hourly quota hit. Body includes upgrade path + reset epoch.
500internalServer-side error. Retry with exponential backoff; if persistent, email support.

Support

Email [email protected] for general help. [email protected] for SLA / Enterprise quotas / on-prem discussions.