---
title: "Resolve"
method: POST
path: "/v1/resolve"
---

# Resolve

`POST /v1/resolve`

## Request

- Base URL: `https://recht.nulegal.eu` (the document declares no server; this is the origin it was published from)
- URL: `https://recht.nulegal.eu/v1/resolve`
- Auth: none declared

Resolve a batch of citations — norms AND decisions — or say honestly why not.

 added the decision half. Until it, an Aktenzeichen or an ECLI came back
`unsupported`, so the Open Assistant's citation gate could existence-check the
statutes a model cited and nothing else: decisions were shown to the reader
without a verified check mark even when the corpus held them.

THE SHAPE IS ADDITIVE. Every key an existing consumer reads is unchanged and
every norm citation resolves exactly as before (`test_resolve_cases_1001.py`
pins both). New keys:

  citation_kind  norm | ecli | docket | fundstelle — which sort of identifier we
                 read the input as. Named `citation_kind` and not `kind` because
                 a norm result's `kind` is already the norm's own ref kind
                 ('para'/'art'); this is the same collision `law_status` was
                 given a distinct name for in, resolved the same way.
  case           the decision, on a resolved decision citation
  preview        its Leitsatz or opening text, ODbL notice attached
  candidates     on `ambiguous` — every decision the citation can mean
  reason/note    on a miss: the machine-readable class and the human sentence

/1016/1029 add four more, all on a resolved NORM result, all additive:

  subdivisions   the subdivision chain as written, values as lists — see
                 `_resolved_norm`. `sub` is unchanged next to it.
  sub_text       the FULL text of the cited Absätze, never truncated
  text_truncated whether `text` is the 300-character stub or the whole thing
  norms          on an enumeration ('§§ 4, 7 KSchG'), every member, with
                 `enumeration` naming the refs and any the corpus lacks

…plus one request field, `include`: `text` swaps a norm's stub for
its full text, `leitsatz` swaps a decision's 294-character preview for the
whole Leitsatz. Both default OFF, so a caller that sends what it always sent
receives what it always received.

`reason` is the agent API's ResolveResult enum verbatim
(not_in_corpus / outside_coverage / unparseable / ambiguous), so the specced
`/agent/v1/resolve` is a re-shape of this payload rather than a second opinion
about the same corpus.

**`status: "attested"`** is the fifth value and the newest. It means:
the corpus does NOT hold this Aktenzeichen, and decisions the corpus DOES hold
prove it exists anyway by citing it — "echt, Text nicht geführt". Before this
key such a docket answered `not_in_corpus`, which an agent verifying a citation
reads as "invented", and for the up to 204,384 dockets our own decisions cite
twice or more that reading is wrong. ("Up to": that count is the nightly
rollup's, and the answer is decided on the live citers still addressable now,
which is the smaller number.)

It is a kind of MISS: there is no `case` and no `preview`, because no decision is
being handed over, and `reason` stays `not_in_corpus`, because the corpus really
was asked and really does not have it. A consumer branching only on `reason`
therefore behaves exactly as it did. What rides along is the evidence:

    {"status": "attested",
     "citation_kind": "docket",
     "reason": "not_in_corpus",
     "citers": 7,                    # decisions of ours citing it, LIVE count
     "court_hint": "BGH",            # INFERRED from how the citations name it
     "decided_hint": "1995-11-08",   # INFERRED, may be null
     "attested_by": [{"doknr", "court", "decided", "aktenzeichen", "url"}, …],
     "sources": [{"source", "url", "court", "decided", "matched_on",
                  "full_text_available"}, …],
     "note": "Kein Volltext … die Existenz … ist durch 7 zitierende
              Entscheidungen des Bestands belegt."}

`attested_by` is at most five citing decisions, each addressable, so the claim
can be checked rather than believed; `citers` is the true total beside it. The
hints are read off citation prose and are leads, not metadata — the same field
with the same caveat `/v1/case`'s `known_missing` body carries, and the same
record behind it. The threshold is two citers: one mention shares one text's
typos, two independent ones are evidence about the world.

`sources` is `/v1/case`'s field of the same name and the same rows:
the OFFICIAL, free sources we matched to this docket, `full_text_available`
marking the ones that carry the decision's text. `[]` when we have found it
nowhere. Saying "we do not hold this text" while knowing where it is published
would be a worse answer than the one this status replaced.

A DOCKET DECIDED INSIDE A JOINED JUDGMENT IS NOT ATTESTED, IT IS RESOLVED. The
Court of Justice hands one judgment down under several case numbers and EUR-Lex
catalogs it under the first, so `C-403/01` names a decision we serve — under
`C-397/01`. Those come back `resolved` with `matched_by: "joined_case"`, the
lead's own `case` payload, and a `joined_with` object naming the lead and
quoting the evidence for the relation. That is the same answer `/v1/case` gives
(as `status: "joined_with"`) and the same answer already gives for the
joined dockets stored as comma lists.

Aktenzeichen only. `case_missing` is keyed by docket, so an ECLI and a
Fundstelle have nothing to look up and those branches are unchanged.

A decision citation is classified BEFORE the norm parser runs — see
`caseresolve.classify` for why that order is the safe one and not the risky one.

## Request body

- ResolveRequest: Send `citations` (a list of citation strings) or `text` (running text). An entry of `citations` that holds several citations keeps its own result and lists the others under `extracted` (at most {resolve_text.MAX_FOUND} per request; `extracted_truncated: true` past that).
  - `citations` string[]
  - `include` string[]
  - `text` string: Running text instead of `citations`: every norm citation, docket, EU case number and ECLI in it is found and resolved, one result each with its `span` [start, end]. `unparsed` lists the remaining stretches that still contain a digit. At most 100 citations are resolved; `truncated: true` says the text held more (and `unparsed` is then empty). Read only when `citations` is absent.

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/nulegal/apis/nu-legal-deutsches-recht-api.md) · [All operations](https://skmtc.dev/nulegal/apis/nu-legal-deutsches-recht-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nulegal/apis/nu-legal-deutsches-recht-api/revisions/b4695d8006b1?raw)
