API Documentation

Integrate DemandAI's legal-document engines into your own systems. Five JSON endpoints, one API key, PII protection built in.

Overview

The DemandAI Public API v1 gives banks, firms, and partners programmatic access to the same AI engines that power the web application — including the triple-check generation pipeline (draft, independent forensic audit, reconcile) and in-memory PII tokenization.

Base URL

https://demandai.pro/api/v1

POST/api/v1/demand-letters

Generate a settlement demand letter through the triple-check pipeline: draft, independent forensic damages audit, reconcile. Party names and document text are PII-tokenized in memory before reaching the AI and re-identified only on the finished letter.

POST/api/v1/case-value

Predict a conservative settlement-value range (low / expected / high) before drafting a demand, with value drivers, risk factors, comparable basis, and full reasoning. Detected identifiers in caseSummary and injuries are PII-tokenized before reaching the AI.

POST/api/v1/negotiation

Analyze an insurer’s offer against the original demand (adequacy, recommendation, defensible counter, leverage points — offerRatio recomputed deterministically) and draft the counter-offer response letter. Detected identifiers in caseSummary and insurer are PII-tokenized before reaching the AI.

POST/api/v1/future-medical

Project future / ongoing medical (life-care) costs as itemized line items. Arithmetic is reconciled deterministically: each totalCost = annualCost × durationYears, and the grand total is the exact sum of the line items. Detected identifiers in injuries, prognosis, and currentTreatment are PII-tokenized before reaching the AI.

POST/api/v1/mortgage-demand

Generate mortgage-servicer correspondence (default notice, acceleration, reinstatement, payoff, FDCPA validation, or general demand) with FDCPA/RESPA compliance guardrails and an independent figures audit. Loan numbers and borrower names are PII-tokenized before the AI. Every letter is a DRAFT for compliance and legal review.

Privacy-first by design. Detected identifiers — names, emails, SSNs, loan and account numbers, addresses — are replaced with tokens in memory before any text reaches the AI, and restored only on the finished output. Detection is automated and best-effort: supply party names in their dedicated fields so every occurrence tokenizes deterministically. If residual identifiers cannot be fully scrubbed, generation is blocked with a 422, and every response reports whether tokenization actually occurred via piiProtected.

Authentication

Every request must carry a DemandAI API key. Keys start with dl_ and are created in the dashboard under Settings → API Keys. Each key carries a set of scopes; an endpoint rejects keys without its required scope (403).

Send the key in either header:

Authorization header
Authorization: Bearer dl_your_api_key
X-API-Key header
X-API-Key: dl_your_api_key
EndpointRequired scope
/api/v1/demand-lettersdocuments:write
/api/v1/case-valuecase-value:read
/api/v1/negotiationnegotiation:write
/api/v1/future-medicalfuture-medical:read
/api/v1/mortgage-demandmortgage:write

Treat API keys like passwords: store them in a secrets manager, never commit them, and never use them in browser-side code. API requests do not use cookies or CSRF tokens — the key is the sole credential.

Endpoints

All endpoints accept POST with a JSON body and return JSON. Full request/response schemas live in the OpenAPI spec.

POST

/api/v1/demand-letters

documents:write

Generate a settlement demand letter through the triple-check pipeline: draft, independent forensic damages audit, reconcile. Party names and document text are PII-tokenized in memory before reaching the AI and re-identified only on the finished letter.

Returns 422 (PII scrub incomplete) if sensitive values in documentsText cannot be fully tokenized — supply clientName/defendantName so every occurrence collapses to a token, then retry.

Request body

FieldTypeRequiredDescription
clientNamestringrequiredClaimant name.
caseType"personal-injury" | "property"optionalDefault personal-injury (premium pipeline). property runs the standard homeowner pipeline.
defendantNamestringoptionalDefendant / at-fault party.
incidentDatestringoptionalISO date — drives the statute-of-limitations check.
incidentLocationstringoptionalWhere the incident occurred.
jurisdictionstringoptionalUS state (name or 2-letter code).
documentsTextstringoptionalPre-extracted text of medical records, bills, police reports (max 800,000 chars).
attorneyobjectoptionalSender letterhead: { name, firmName, firmAddress, phone, email, barNumber }.

Example — curl

bash
curl -X POST https://demandai.pro/api/v1/demand-letters \
  -H "Authorization: Bearer dl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "caseType": "personal-injury",
    "clientName": "Jane Doe",
    "defendantName": "John Roe",
    "incidentDate": "2026-01-15",
    "jurisdiction": "OH",
    "documentsText": "--- DOCUMENT: er-bill.pdf ---\nGrant Medical Center ER 01/15/2026. CPT 99284: $1,850.00 ...",
    "attorney": { "name": "Alex Counsel", "firmName": "Counsel & Associates LLP" }
  }'

Example — fetch

javascript
const res = await fetch('https://demandai.pro/api/v1/demand-letters', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEMANDAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    caseType: 'personal-injury',
    clientName: 'Jane Doe',
    defendantName: 'John Roe',
    incidentDate: '2026-01-15',
    jurisdiction: 'OH',
    documentsText: erBillText,
  }),
})
const { letter, demandAmount, audit, demandStrength } = await res.json()

Response — 200

json
{
  "success": true,
  "letter": "…full demand letter…",
  "demandAmount": 187500,
  "figures": {
    "medicalExpenses": 28500,
    "economicDamages": 42500,
    "nonEconomicDamages": 114000,
    "multiplier": 4,
    "punitiveDamages": 0
  },
  "audit": {
    "completed": true,
    "mathVerified": true,
    "corrected": false,
    "discrepancies": []
  },
  "caseStrength": "Strong",
  "confidence": 0.92,
  "demandStrength": 82,
  "strengthLabel": "Strong",
  "statuteOfLimitations": { "status": "ok", "…": "…" },
  "piiProtected": true,
  "modelUsed": "claude-opus-4-8",
  "processingTimeMs": 148213
}
POST

/api/v1/case-value

case-value:read

Predict a conservative settlement-value range (low / expected / high) before drafting a demand, with value drivers, risk factors, comparable basis, and full reasoning. Detected identifiers in caseSummary and injuries are PII-tokenized before reaching the AI.

Returns 422 (PII scrub incomplete) if detected identifiers in caseSummary/injuries cannot be fully tokenized — remove names and identifiers, then retry.

Request body

FieldTypeRequiredDescription
caseSummarystringrequiredFacts of the matter.
jurisdictionstringoptionalUS state — applies fault rules and damage caps.
injuriesstringoptionalInjury description.
medicalSpecialsnumberoptionalDocumented medical specials in dollars.
liability"clear" | "disputed" | "shared"optionalLiability posture.

Example — curl

bash
curl -X POST https://demandai.pro/api/v1/case-value \
  -H "Authorization: Bearer dl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "caseSummary": "Rear-end collision at a stoplight; 4 months of treatment.",
    "jurisdiction": "TX",
    "medicalSpecials": 28500,
    "liability": "clear"
  }'

Example — fetch

javascript
const res = await fetch('https://demandai.pro/api/v1/case-value', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEMANDAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    caseSummary: 'Rear-end collision at a stoplight; 4 months of treatment.',
    jurisdiction: 'TX',
    medicalSpecials: 28500,
    liability: 'clear',
  }),
})
const { prediction } = await res.json()

Response — 200

json
{
  "success": true,
  "prediction": {
    "low": 65000,
    "expected": 95000,
    "high": 130000,
    "confidence": 0.78,
    "valueDrivers": ["Clear liability", "Documented specials"],
    "riskFactors": ["Soft-tissue component"],
    "comparableBasis": "3x-4x specials band for moderate injuries…",
    "reasoning": "…"
  },
  "piiProtected": false,
  "modelUsed": "claude-sonnet-4-6",
  "processingTimeMs": 21874
}
POST

/api/v1/negotiation

negotiation:write

Analyze an insurer’s offer against the original demand (adequacy, recommendation, defensible counter, leverage points — offerRatio recomputed deterministically) and draft the counter-offer response letter. Detected identifiers in caseSummary and insurer are PII-tokenized before reaching the AI.

Returns 422 (PII scrub incomplete) if detected identifiers in caseSummary cannot be fully tokenized — remove names and identifiers, then retry.

Request body

FieldTypeRequiredDescription
demandAmountnumberrequiredOriginal settlement demand in dollars (> 0).
offerAmountnumberrequiredInsurer’s offer in dollars (≥ 0).
caseSummarystringrequiredFacts supporting the demand.
insurerstringoptionalCarrier name.

Example — curl

bash
curl -X POST https://demandai.pro/api/v1/negotiation \
  -H "Authorization: Bearer dl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "demandAmount": 250000,
    "offerAmount": 62500,
    "caseSummary": "Clear-liability collision; $48k documented specials.",
    "insurer": "Acme Mutual"
  }'

Example — fetch

javascript
const res = await fetch('https://demandai.pro/api/v1/negotiation', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEMANDAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    demandAmount: 250000,
    offerAmount: 62500,
    caseSummary: 'Clear-liability collision; $48k documented specials.',
    insurer: 'Acme Mutual',
  }),
})
const { analysis, responseLetter } = await res.json()

Response — 200

json
{
  "success": true,
  "analysis": {
    "offerAmount": 62500,
    "demandAmount": 250000,
    "offerRatio": 0.25,
    "adequacy": "lowball",
    "recommendation": "counter",
    "suggestedCounter": 225000,
    "leveragePoints": ["Clear liability", "…"],
    "reasoning": "…"
  },
  "responseLetter": "…full counter-offer letter…",
  "piiProtected": true,
  "modelUsed": "claude-opus-4-8",
  "processingTimeMs": 64110
}
POST

/api/v1/future-medical

future-medical:read

Project future / ongoing medical (life-care) costs as itemized line items. Arithmetic is reconciled deterministically: each totalCost = annualCost × durationYears, and the grand total is the exact sum of the line items. Detected identifiers in injuries, prognosis, and currentTreatment are PII-tokenized before reaching the AI.

Returns 422 (PII scrub incomplete) if detected identifiers in injuries/prognosis/currentTreatment cannot be fully tokenized — remove names and identifiers, then retry.

Request body

FieldTypeRequiredDescription
injuriesstringrequiredInjury description.
prognosisstringoptionalMedical prognosis.
claimantAgenumberoptionalClaimant age in years — drives the projection horizon.
currentTreatmentstringoptionalCurrent / past treatment.
jurisdictionstringoptionalUS state.

Example — curl

bash
curl -X POST https://demandai.pro/api/v1/future-medical \
  -H "Authorization: Bearer dl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "injuries": "L4-L5 disc herniation, status post microdiscectomy",
    "prognosis": "Likely future fusion within 10-15 years",
    "claimantAge": 42
  }'

Example — fetch

javascript
const res = await fetch('https://demandai.pro/api/v1/future-medical', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEMANDAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    injuries: 'L4-L5 disc herniation, status post microdiscectomy',
    prognosis: 'Likely future fusion within 10-15 years',
    claimantAge: 42,
  }),
})
const { projection } = await res.json()

Response — 200

json
{
  "success": true,
  "projection": {
    "lineItems": [
      {
        "treatment": "Anticipated lumbar fusion surgery",
        "frequency": "one-time",
        "durationYears": 1,
        "annualCost": 85000,
        "totalCost": 85000
      }
    ],
    "totalFutureMedical": 142600,
    "lifeCareSummary": "…demand-ready narrative…",
    "assumptions": ["…"],
    "confidence": 0.72
  },
  "piiProtected": false,
  "modelUsed": "claude-sonnet-4-6",
  "processingTimeMs": 30412
}
POST

/api/v1/mortgage-demand

mortgage:write

Generate mortgage-servicer correspondence (default notice, acceleration, reinstatement, payoff, FDCPA validation, or general demand) with FDCPA/RESPA compliance guardrails and an independent figures audit. Loan numbers and borrower names are PII-tokenized before the AI. Every letter is a DRAFT for compliance and legal review.

At least one of documentsText, borrowerName, loanNumber, or totalArrears is required. Returns 422 (PII scrub incomplete) if borrower PII in documentsText cannot be fully tokenized.

Request body

FieldTypeRequiredDescription
letterTypestringoptionaldefault-notice (default) | acceleration | reinstatement-demand | payoff-demand | fdcpa-validation | general-demand.
servicerstringoptionalServicer / sender name (letterhead).
borrowerNamestringoptionalBorrower name (tokenized).
coBorrowerNamestringoptionalCo-borrower name (tokenized).
loanNumberstringoptionalLoan number (tokenized).
propertyAddressstringoptionalProperty address (tokenized).
defaultDatestringoptionalDate of default.
totalArrearsstring | numberoptionalTotal arrears in dollars.
perDiemstring | numberoptionalPer-diem interest.
reinstatementAmountstring | numberoptionalReinstatement figure.
payoffAmountstring | numberoptionalPayoff figure.
investorstringoptionalInvestor / owner of the loan (tokenized).
jurisdictionstringoptionalUS state.
documentsTextstringoptionalPre-extracted text of loan documents (max 800,000 chars).

Example — curl

bash
curl -X POST https://demandai.pro/api/v1/mortgage-demand \
  -H "Authorization: Bearer dl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "letterType": "default-notice",
    "servicer": "First Example Servicing LLC",
    "borrowerName": "Jane Q. Borrower",
    "loanNumber": "0012345678",
    "totalArrears": "8420.55",
    "jurisdiction": "OH"
  }'

Example — fetch

javascript
const res = await fetch('https://demandai.pro/api/v1/mortgage-demand', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEMANDAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    letterType: 'default-notice',
    servicer: 'First Example Servicing LLC',
    borrowerName: 'Jane Q. Borrower',
    loanNumber: '0012345678',
    totalArrears: '8420.55',
    jurisdiction: 'OH',
  }),
})
const { letter, figures, figuresVerified } = await res.json()

Response — 200

json
{
  "success": true,
  "letter": "…DRAFT letter for compliance review…",
  "figures": {
    "totalArrears": 8420.55,
    "perDiem": 21.4,
    "reinstatementAmount": 8420.55,
    "payoffAmount": 0,
    "lateFees": 316.82
  },
  "figuresVerified": true,
  "auditCompleted": true,
  "letterType": "default-notice",
  "discrepancies": [],
  "piiProtected": true,
  "modelUsed": "claude-opus-4-8",
  "processingTimeMs": 121540
}

Rate Limits

Generation endpoints run expensive multi-pass AI pipelines, so v1 requests share a single per-key bucket of 50 requests per hour across all five endpoints (or your key's configured hourly / daily / monthly limits, whichever is lower). The limit is enforced per authenticated key, so it follows the key — not the header style or source IP. Repeated failed authentication attempts from one IP are rate-limited separately, and platform-level protection additionally limits each source IP to roughly 100 API requests per minute.

When a limit is exceeded the API returns 429 with a Retry-After header (seconds) — wait at least that long before retrying:

json
{
  "error": "Too many requests",
  "message": "Rate limit exceeded. Please try again later.",
  "retryAfter": 1740
}

Need higher throughput for a production integration? Contact us via support to discuss partner limits.

Errors

Every error response uses one JSON envelope: { "error": "...", "message": "..." }. The error field is a stable category; message explains what to fix.

StatuserrorMeaning
400Invalid requestMalformed JSON, or a missing / invalid field. The message names the field.
401UnauthorizedMissing, malformed, expired, or inactive API key.
403Insufficient scopeValid key, but it does not carry the scope the endpoint requires, the owning account lacks API access, or an IP / user-agent restriction on the key blocked the request.
422PII scrub incompleteGeneration was blocked because detected identifiers in the request could not be fully tokenized. Supply the party names in their fields (or remove stray identifiers) and retry.
429Too many requestsRate limit exceeded. Honor the Retry-After header before retrying.
500Internal errorUnexpected failure. Safe to retry.
Machine-readable spec: /api/v1/openapi.json · Manage keys in Settings → API Keys