---
title: "Draft case document (E2)"
method: POST
path: "/api/v1/cases/{caseId}/draft"
tags: ["Cases"]
---

# Draft case document (E2)

`POST /api/v1/cases/{caseId}/draft`

## Request

- Base URL: `https://legal.nexusquantum.legal`
- URL: `https://legal.nexusquantum.legal/api/v1/cases/{caseId}/draft`
- Auth: HTTP bearer

Drafts a legal document from the case context. Jurisdiction is INHERITED from the case (NOT a parameter). The internal route's SSE is aggregated to JSON server-side. Loopback: the internal route is the only one that debits (3 cr × tier multiplier).

## Path parameters

- `caseId` string, uuid, required

## Request body

- object
  - `docType` string: Document type (e.g. complaint, appeal).
  - `customType` string: Free-text type description when docType does not fit.
  - `instructions` string
  - `language` 'es' | 'en' | 'fr' | 'de'
  - `modelTierId` string

## Response `200`

{ draft, citationChecks?, truncated?, chunksUsed?, chunksTotal?, corpusPartial?, piiResiduals?, citationsOrigenC[], killSwitch?, processingMs, requestId }. `draft` is the FINISHED text: personal data rehydrated and, when the document was cut short, the notice written INSIDE the body — not the raw model stream. ⚠️ `truncated: false` means the provider reported a clean stop. It does NOT mean completeness was verified: a provider that omits `finish_reason` — which the API permits, and under BYO the provider is the one your firm chose — produces text that stops mid-sentence and still arrives as `truncated: false`. `chunksTotal` is the denominator: without it, `chunksUsed: 48` reads as the whole case file and may be 48 of 1,200. `null` there means the count could not be taken, which is NOT «there are no more». `piiResiduals` are anonymisation markers that could not be restored: the draft ships with placeholders where personal data belongs. `piiResidualsFromCorpus` vs `piiResidualsInvented` split the same markers by ORIGIN, because the actions are opposite: FROM-CORPUS means the marker was already in the case-file document and the map that would undo it is never stored (Zero Retention) — unrecoverable BY DESIGN, the privacy guarantee working, and only the firm can fill it in from its own source. INVENTED means the marker appears nowhere in the case file: the engine produced it and there is NO underlying value — delete or replace it, never read it as masked case data. Both are also written INTO `draft`, because a .docx that leaves the firm does not carry these fields. `citationsOrigenC` are citations absent from the case corpus — possible invention. `killSwitch` is `null` when the output watchdog ran and did not fire; absent means it was not run. It reports; it does not block.

- object
  - `draft` string
  - `citationChecks` CitationVerificationSummary
    - `checks` CitationCheck[], required
      - `citation` string, required: Citation exactly as it appeared in the analysis.
      - `kind` 'L4-N' | 'L2-J', required: Legislation (L4-N) or case law (L2-J).
      - `status` 'verified' | 'mismatch' | 'not_found' | 'derogated' | 'pending' | 'not_verifiable', required: verified=exists and matches; mismatch=exists but diverges; not_found=absent from the active corpus; not_verifiable=jurisdiction with no active corpus; pending=not parseable.
      - `similarity` number, nullable, required: Lexical similarity (Jaccard) against the canonical text.
      - `semantic` number, nullable, required: Semantic similarity (cosine), only in the lexical gray zone.
      - `url` string, nullable, required: Official source URL for THAT jurisdiction when one is located (BOE · CENDOJ · Singapore Statutes Online · eLitigation · SUIN-Juriscol…).
      - `mismatchKind` 'meaning' | 'stitched' | 'lexical' | 'party': Only with `status: mismatch`, and ADDITIVE (may be missing from older checks). Grades the severity, which used to be lost: `meaning` = a meaning veto fired (negation, modality, quantifier, omitted exception, subject) → a REAL divergence of meaning. `stitched` = the quoted fragments are literal but do not come from a CONTINUOUS passage of the official text, or they alter its order — an ASSEMBLED quote. The defect is structural: a divergence of meaning has NOT been proven, so it must not be presented as one (added 2026-07-25; measured by contiguity since 2026-07-27). `lexical` = only the lexical ratio failed: an honest paraphrase that cannot be checked literally. `party` = the citation EXISTS but resolves to a DIFFERENT decision from the one the text names (incompatible party names — typically a transposed court, e.g. `Spandeck … [2007] SGHC 37` when the case is SGCA 37). It is neither a non-existent citation nor a divergence of meaning: it points elsewhere. `similarity` comes back `null` on purpose — the claim is not compared against a decision that is not the one named (added 2026-07-27).
      - `note` string, nullable: Human-readable note from the verifier (deterministic, server-side — never from the model). E.g. STATUTE-LEVEL verification of a law cited without an article, or the notice that the registry proved existence without returning the text.
      - `canonicalText` string, nullable: Official text the verifier downloaded to check the citation against, when the corpus returns it. For case law this is the full judgment: truncate it before displaying.
    - `counts` object, required: Count per status.
    - `anyBroken` boolean, required: There is at least one broken citation (mismatch/not_found/derogated). EXCLUDES `pending` (not parseable) and `not_verifiable` (jurisdiction with no active corpus): those statuses are NOT breakages. READ `composition` BEFORE ACTING ON THIS: `anyBroken: false` means every citation is faithful to its source ONE BY ONE. It does NOT mean the argument they support holds — the inferential step that joins them is not verified by this field.
    - `composition` object: SCOPE OF THE COMPOSITION — what `anyBroken` cannot tell you. Verifying each citation proves fidelity to its source; it says nothing about the step that JOINS them. Two impeccable citations can support a false conclusion. This object carries the axes of that step that ARE decidable without understanding the argument — repealed premises, premises not yet in force, and above all validity windows that never overlapped (a defect invisible when citations are checked one at a time) — and, just as important, the axes that are NOT checked, each with its reason. IT IS ALWAYS PRESENT, including when there are no findings: if it appeared only on problems, its absence would again mean "this is fine", which is the reading it exists to prevent. `no_comprobado` permanently includes `validez_logica`: WHETHER THE CONCLUSION FOLLOWS FROM THE PREMISES IS NOT CHECKED, and that is not a pending task — it is not a mechanically decidable question. An empty `hallazgos` is not a statement that the reasoning is valid.
      - `comprobado` string[]: Axes actually examined. An axis only enters here if there was MATERIAL for it to produce a finding — never merely because the code ran.
      - `hallazgos` object[]: ANOMALIES. Named, never an aggregate boolean. A fact only qualifies as a finding if it is measurably RARE in correct work — see `observaciones` for the ones that are not.
        - `eje` string
        - `clase` 'ventanas_sin_solape' | 'premisa_derogada' | 'premisa_no_nacida' | 'fuera_de_fecha' | 'fuera_de_territorio' | 'sin_autoridad_vinculante'
        - `citas` string[]
        - `detalle` string
        - `no_afirma` string: What the finding does NOT assert. Travels with it so it cannot be quoted alone as a verdict.
      - `observaciones` object[]: FACTS ABOUT THE SET THAT ARE NOT ANOMALIES, each carrying its measured base rate. Citing authority from another British forum fires on 49.71% of real Scottish and Northern Irish judgments, and in 18.21% every authority cited is from another forum (7,494 judgments, 23,334 resolved citations, measured 2026-08-15) — it is normal practice, so reporting it as a finding would train integrators to ignore the findings that matter. Treat these as checklist items, not defects. `hallazgos: []` WITH a populated `observaciones` is a NORMAL result, not a clean one.
        - `eje` string
        - `clase` 'autoridad_de_otro_foro'
        - `citas` string[]
        - `detalle` string
        - `base_medida` string: How often this appears in CORRECT work, with the measurement behind it.
        - `no_afirma` string
      - `no_comprobado` object[]: Axes not examined and why. `validez_logica` is permanently here and is NOT decidable; the rest appear only when the data for them was absent, each with its reason.
        - `eje` string
        - `motivo` string
      - `sin_dato` object[]: Citations left out of a comparison for lack of data. A missing datum never becomes a finding.
        - `eje` string
        - `citas` string[]
    - `total` integer, required: Number of verifiable citations detected.
    - `error` boolean: ADDITIVE and optional; present (and always `true`) ONLY when the deterministic verification COULD NOT RUN at all (exception, timeout, corpus unreachable). READ IT BEFORE `anyBroken` or `counts`: with `error: true` the summary carries `total: 0`, `anyBroken: false` and all counters at zero — that is FILLER, not a verdict. It means "the citations were NOT checked", NOT "the citations were checked and are clean". Treat every citation in the answer as unverified and review it against the official source. It is a new optional FIELD on purpose, never a new value inside the closed `status` enum, so integrators that `switch` on status do not break. Absent on every successful verification.
    - `unverifiableClaims` integer: ADDITIVE and optional (present only when > 0). Number of legal assertions written in PROSE that invoke authority without a formal, parseable citation ("as the Court held in Vega, the appeal was dismissed"). No parser extracts them, so they never appear in `checks` and never count as broken — but with `total: 0` they are the difference between "no citations" and "authority claimed with nothing to check it against". Use it for a caution, never to mark a citation verified or not_found.
    - `coverage` object: WHAT COULD BE LOOKED AT, not just what was found. Read this BEFORE `counts` or `anyBroken`. Three situations used to reach the client indistinguishable: a report with no authorities to verify, a report whose citations were all checked, and a report that ASSERTS doctrine with no recognisable citation apparatus — so nothing could be checked at all. The third one is the dangerous one and it is what any prose without citation apparatus produces.
      - `state` 'checked' | 'partially_checked' | 'no_authority' | 'unverifiable' | 'not_measured' | 'check_failed', required: `checked` = there were citations and they were contrasted (see `checks`), and nothing else in the text asserts authority. `partially_checked` = there were citations AND ALSO statements attributing holdings to courts with no checkable reference of their own. The green verdict on the citations does NOT cover those: a single verifiable citation anywhere in the document (an appendix table of authorities, say) must not be readable as a verdict on the whole body. `no_authority` = neither citations nor authority claims: there was genuinely nothing to verify. `unverifiable` = the text attributes holdings or doctrine to courts WITHOUT any checkable reference, so NOTHING was contrasted against the corpus. This is NOT a statement that the content is wrong — it is a statement that it is unverified, which is not the same as a clean report. `not_measured` = no citation found AND the report's language has no authority-claim lexicon, so the zero is a not-measured, not a "none". `check_failed` = the verifier itself could not run (mirrors `error: true`).
      - `citations` integer, required: Citations the verifier was able to look at (equals `total`).
      - `authorityClaims` integer, required: Statements attributing a holding or settled doctrine to an authority with no checkable citation in the same sentence.
      - `examples` string[]: Up to three of those statements, truncated. Present only when there are any: "there are 4" without saying which is not actionable.
      - `language` string, required: Language the report was produced in, as resolved by the platform. Decides whether a zero in `authorityClaims` is measurable.
  - `truncated` boolean: The model stopped mid-output (`finish_reason` length/max_tokens): what is missing was NOT written. `draft` carries the same notice inside its body, because exports (.docx/.pdf/clipboard) do not carry this JSON. Do not use or file it without completing it. `false` asserts the text is complete.
  - `chunksUsed` integer: Case fragments that entered the prompt.
  - `chunksTotal` integer, nullable: Fragments the case holds. null = could not be counted.
  - `corpusPartial` boolean: chunksUsed < chunksTotal: the draft saw only part of the case.
  - `piiResiduals` string[]: All unrestored anonymisation markers (flat list).
  - `piiResidualsFromCorpus` string[]: Markers that came from the case-file document: unrecoverable BY DESIGN (Zero Retention discards the map). Not a drafting failure — the firm fills them in from its own source.
  - `piiResidualsInvented` string[]: Markers absent from the case file: the engine produced them and there is no data behind them. Delete or replace — do NOT read as masked case data.
  - `citationsOrigenC` string[]
  - `killSwitch` object, nullable: Output watchdog. A lexical scan of the generated text for high-risk language (irrevocable waivers, apparent forgery, undisclosed conflicts, ouster of jurisdiction…). Codes are `W-OUT-1`…`W-OUT-9`, plus `S-LEG-STOP` when the model itself raised a halt. It does NOT block delivery — it reports. `null` = ran and did not fire; absent = not run. Lexicon covers ES/EN only.

## Other responses

- `400`: VALIDATION_ERROR | INVALID_CASE_ID
- `402`: INSUFFICIENT_CREDITS | SPEND_CAP_REACHED
- `403`: Case does not belong to the API key owner.
- `404`: CASE_NOT_FOUND — case not found.
- `429`: RATE_LIMITED
- `502`: UPSTREAM_ERROR — the internal route did not emit a done event.

---

[API](https://skmtc.dev/nexusquantum/apis/nexus-legal-api.md) · [All operations](https://skmtc.dev/nexusquantum/apis/nexus-legal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nexusquantum/apis/nexus-legal-api/revisions/4084d8d4eb0b?raw)
