---
title: "Verification Center — analyzes a document and verifies its citations (legislation + case law, multi-jurisdictional)"
method: POST
path: "/api/v1/verificacion/analizar"
tags: ["Legislation"]
---

# Verification Center — analyzes a document and verifies its citations (legislation + case law, multi-jurisdictional)

`POST /api/v1/verificacion/analizar`

## Request

- Base URL: `https://legal.nexusquantum.legal`
- URL: `https://legal.nexusquantum.legal/api/v1/verificacion/analizar`
- Auth: HTTP bearer

Automatically extracts the citations from a text —legislation AND case law—, deduplicates them and verifies each one against the corpus of ITS jurisdiction as of the given date. Deterministic: regex + force-status RPC only, 0 LLM, 0 credits. Returns counts (found/not_found/derogated/unknown), the flagged breakdown (`flagged`, `verified_clean`, `review_required`, `counts_by_meaning`) and an array of results with status, reproach, canonical text and official URL. DO NOT READ `found` AS 'CLEAN': it counts citations that EXIST, and a citation can exist and still resolve to a different decision from the one the document names (`results[i].meaning: "other_case"`). The clean count is `verified_clean`; the single boolean to branch on is `review_required`, mirrored in the `X-Nexus-Verification` header. SCOPE (changed 2026-07-25): NO LONGER BOE-only. Each citation's jurisdiction is inferred from its SHAPE (`section 80 of the Employment Act 1968` → SG; `art. 1902 CC` → ES/CO) and routed to the matching verifier; there is NO default jurisdiction and nothing falls back to ES. `jurisdiction` is OPTIONAL and only disambiguates citations that are valid in several jurisdictions. Citations whose jurisdiction cannot be determined come back as `unknown` (honest), never invented. The response ALWAYS includes `verifiable_jurisdictions` so that a `total:0` is checkable instead of silent. Max. 100 citations and 50,000 chars per request.

## Request body

- object
  - `text` string, required: Text of the document to verify (~30 pages max).
  - `date` string, date: Force-status date (YYYY-MM-DD). Default today.
  - `fecha` string, date: Force-status date (YYYY-MM-DD). Default today.
  - `jurisdiction` string: OPTIONAL and with no default. Only needed to disambiguate a citation that is valid in several jurisdictions (e.g. `art. 1902 CC` → ES/CO). If omitted, each citation is routed by its shape.

## Response `200`

Verification result — see `VerificacionResponse`.

READ IT IN THIS ORDER: `review_required` (or the `X-Nexus-Verification` header) → `verified_clean` / `flagged` → `results[i]` with `status` AND `meaning` together. `found` counts citations that EXIST, flagged ones included, so it is not the clean count and never was: a brief whose only citation names the wrong court comes back `found: 1, not_found: 0`.

SCOPE OF THE CHECK — compare `citations_detected` (citations FOUND in the document) with `citations_checked` (`total`, the ones actually checked): the per-request cap is 100, and a longer brief is checked on the first 100 only. When they differ, `citations_truncated` says so; the unchecked citations do NOT appear in `results` at all, and their absence is not a clean bill of health — split the document and send it in parts. `text_truncated` reports the other cap (50,000 chars). `verifiable_jurisdictions` lists the jurisdictions that have a verifier wired up today, so a `total: 0` is checkable instead of silent.

- VerificacionResponse: Result of the Verification Center over one document. 🔴 THE HEADLINE COUNTERS ARE NOT A VERDICT. `found` counts every citation that EXISTS in the corpus, including the ones carrying a reproach — deliberately, because the statement "this citation exists" stays true when it resolves to another decision. So a document whose only citation names the wrong court comes back `found: 1, not_found: 0`. Read `review_required` (or the `X-Nexus-Verification` response header) first, and `verified_clean` / `flagged` instead of `found` when you need the clean count. Invariant: `found === verified_clean + flagged`.
  - `date` string, date: English twin of `fecha`. Either works; neither is retired.
  - `fecha` string, date, required: Date the force-status was evaluated at (YYYY-MM-DD).
  - `total` integer, required: Citations actually checked (same value as `citations_checked`).
  - `found` integer, required: Citations that EXIST in the corpus — flagged ones INCLUDED. Not the clean count: that is `verified_clean`.
  - `not_found` integer, required: Citations absent from the active corpus.
  - `derogated` integer, required: Citations that existed but are not in force on `fecha`.
  - `unknown` integer, required: Citations that could not be checked. A gap, not a pass.
  - `results` VerificacionResult[], required
    - `raw` string, required: The citation exactly as it appears in the document.
    - `alias` string, nullable, required: Recognised alias of the piece of legislation (ES/BOE pass), e.g. `CC`, `LEC`. `null` for case law and for citations resolved by the jurisdiction-agnostic pass.
    - `norma_label` string, nullable, required: Human-readable name of the legislation behind `alias`. `null` when there is no alias.
    - `numero_articulo` string, required: Article/section number, when the citation carries one. Empty string when it does not (a whole statute, or a judgment).
    - `status` 'found' | 'not_found' | 'derogated' | 'unknown', required: `found` = the citation EXISTS in the corpus of its jurisdiction. It is NOT a clean bill of health on its own: check `meaning`. `not_found` = it is absent from the active corpus. `derogated` = it existed but is not in force on `fecha`. `unknown` = it could not be checked (see `unknown_reason`) — a gap, never a pass. This enum is CLOSED and stays at four values: everything added since travels in additive optional fields, so a `switch` written against it keeps compiling. The price of that promise is that the enum cannot tell you the whole verdict by itself.
    - `content_checked` false: PRESENT AND `false` = the verdict establishes that the provision EXISTS, and the WORDING your document attributes to it was never compared against the official text. ABSENT = the content was compared (or the comparison does not apply). The field only appears when there is something to warn about, so `content_checked === false` is the test, not its truthiness. This is the case for the whole of the United Kingdom, where content comparison is deliberately not enabled. Until 2026-08-18 this fact travelled only inside the prose of `note`, behind the literal string `CONTENT NOT CHECKED`, and a client had to match on that string to recover it. It is the difference between «this section exists» and «this section says what you claim», which for a citation-checking product is the whole distinction.
    - `meaning` 'other_case' | 'diverges' | 'paraphrase': REPROACH on a citation that exists (so `status` is `found`). PRESENT ⇒ the row is flagged. **ABSENT DOES NOT MEAN CLEAN**: since v1.40.0 a row can be flagged by `party_check: "partial"` with no `meaning` at all. The exact predicate is `status === "found" && (meaning || party_check === "partial")`. `other_case` — the citation EXISTS but resolves to a DIFFERENT decision from the one the document names (incompatible party names, typically a transposed court: `Spandeck … [2007] SGHC 37` where the case is `[2007] SGCA 37`). NOTHING WAS COMPARED about the sense of the quotation: the defect is the IDENTITY of the authority, and `similarity` is deliberately left unmeasured. Do not present it as a paraphrase — it points somewhere else. `note` names the decision it actually resolves to and, when found, the sibling citation that does match. `diverges` — a meaning veto fired against the official text (negation, modality, quantifier, omitted exception, subject): a REAL divergence of sense. `paraphrase` — only the lexical ratio failed, or the quoted fragments are literal but assembled from non-continuous passages. A divergence of meaning has NOT been proven; it could not be checked literally. Use `mismatch_kind` to tell the two apart. Earlier versions of this document described the field as appearing "when the citation exists but the attributed sense does not match" and listed only two values. That was false for `other_case`, where no sense is compared at all.
    - `vigencia_desde` string, date, nullable: Date the provision came into force, when the verifier measured in-force status unambiguously. Present on `derogated` rows (ES/CO always; UK legislation since v1.41.0, repealed or not-yet-in-force alike) and on UK `found` rows confirmed currently in force. Absent = in-force status not measured for this row — never read absence as "in force with no known date".
    - `vigencia_hasta` string, date, nullable: Date the provision ceased to be in force (repeal date). Present only when the row is `derogated` for having been repealed — absent for a provision that never yet came into force.
    - `party_check` string, nullable: State of the PARTY-NAME contrast, where the jurisdiction performs one. Values are ADDITIVE and the list is OPEN: `match` · `no_name` · `unavailable` · `mismatch` · `partial`. Treat an unknown value as FLAGGED, never as clean. 🔴 `partial` FLAGS THE ROW ON ITS OWN, WITHOUT `meaning`. It means: the decision exists, but a party the document names appears neither in the name the record gives that decision nor in its text — identity half-confirmed. It does NOT assert the citation is wrong (the record may list only the lead party; you may be using an acronym; it may be a joined appeal) and it does NOT confirm it either. `note` carries the reason in prose. Travels separately from `meaning` deliberately: «a party you name does not appear» is NOT «resolves to another decision», and asserting the latter would be a reproach we cannot sustain.
    - `mismatch_kind` 'lexical' | 'meaning' | 'stitched' | 'party': The engine's reproach VERBATIM, before `meaning` collapses it. `stitched` and `lexical` both map to `meaning: "paraphrase"`, so without this field the two are indistinguishable on the wire and a formatter has to guess which one it is holding. `party` → `meaning: "other_case"`. `meaning` → `meaning: "diverges"`. `stitched` (literal fragments assembled from non-continuous passages, or reordered) and `lexical` (ratio only) → `meaning: "paraphrase"`. ADDITIVE and open to growth: treat an unrecognised value as flagged, never as clean.
    - `canonical_text` string, nullable, required: Official text the citation was checked against, trimmed to what is worth reading. `null` when the corpus returned no text.
    - `canonical_truncated` boolean, required: `true` when `canonical_text` stops short of the full official text: the rest of the article or judgment exists but is NOT written in this response. Do not read the excerpt as the whole provision, and do not conclude from it that the citation covers nothing else. `false` asserts the official text travels whole.
    - `url` string, nullable, required: Official source URL for that jurisdiction when one is located (BOE · CENDOJ · Singapore Statutes Online · eLitigation · SUIN-Juriscol…).
    - `context` string, required: The surrounding sentence of the document, so the citation can be located without the source file.
    - `kind` 'norma' | 'jurisprudencia', required: What was cited: legislation or case law. Without it a judgment gets reported as an "article not found in the corpus", which is a category error on top of the finding.
    - `note` string, nullable: Deterministic, server-side explanation of the verdict — never model prose. THE MOST ACTIONABLE PART OF A FLAGGED ROW: it says which decision the citation actually resolves to, and where the correct citation is. Render it; do not drop it.
    - `unknown_reason` 'not_verifiable' | 'error': Why the row is `unknown`, which used to collapse two different things. `not_verifiable` = no corpus is wired up for that jurisdiction/alias — a stable property of coverage you can decide with. `error` = the check ran and broke — ours, and worth retrying. Neither is a pass.
  - `flagged` integer, required: Citations that exist but carry a reproach: rows with `results[i].meaning` PLUS rows with `results[i].party_check === "partial"` (identity half-confirmed, which has no `meaning`). They resolve to another decision, distort the text, are unverifiable paraphrases, or name a party that does not appear in the decision. The counter exists because the truth used to live only inside `results[i].meaning` and in the prose of `note`, while the header said `found: 1, not_found: 0` — and an integrator reads the header, which is what a header is for.
  - `verified_clean` integer, required: `found` minus `flagged`: the citations that came back clean. This is the number to show as "verified".
  - `review_required` boolean, required: The one question an integrator asks: can I proceed without looking? `false` ONLY when nothing is flagged, nothing is missing, nothing is derogated, nothing was uncheckable and nothing fell outside the per-request cap. A gap counts as a reason to look: "could not be checked" is not "is fine". Mirrored on every response in the `X-Nexus-Verification` header (`review-required` | `clean`) so you can branch without parsing the body.
  - `counts_by_meaning` object, required: Breakdown of the `meaning` reproaches ONLY, so `other_case + diverges + paraphrase` is **≤ `flagged`**, not equal to it: the difference is the identity-half-confirmed rows (`party_check: "partial"`), which carry no `meaning`. Until v1.40.0 this said «sums to `flagged`»; that invariant no longer holds. Do NOT reconcile this breakdown against `flagged` to infer a bug on our side. Always present; zeros are real zeros.
    - `other_case` integer, required: Citations that resolve to a DIFFERENT decision from the one named.
    - `diverges` integer, required: Citations whose attributed sense diverges from the official text.
    - `paraphrase` integer, required: Citations that could not be checked literally (paraphrase or assembled quotation).
  - `verifiable_jurisdictions` string[], required: Jurisdictions with a verifier wired up TODAY. Always declared, so a `total: 0` can be checked against your own jurisdiction instead of being read as "clean document".
  - `citations_detected` integer, required: Citations FOUND in the document.
  - `citations_checked` integer, required: Citations actually CHECKED (== `total`). Compare it with `citations_detected`: when they differ, the per-request cap applied.
  - `citations_truncated` object: Present ONLY when the per-request cap (100 citations) cut the document short. The unchecked citations do NOT appear in `results` at all, and their absence is not a clean bill of health — split the document and send it in parts.
    - `code` 'CITATION_LIMIT_REACHED', required: Machine contract: branch on this, not on the prose.
    - `limit` integer, required
    - `detected` integer, required
    - `checked` integer, required
    - `unchecked` integer, required
    - `message` string, required: English explanation for the integrator's on-call human. The UI renders its own translated notice.
  - `text_truncated` boolean: Present (and always `true`) when the document exceeded 50,000 characters and only the first 50,000 were analysed: the citations in the remainder were NOT looked at and appear nowhere in this response — their absence from `results` is not a clean bill of health. Absent otherwise. Without this field a 90-page brief comes back the same shape as one reviewed in full.
  - `requestId` string: Same value as the `X-Request-Id` response header. Quote it in support.

## Other responses

- `400`: MISSING_TEXT | INVALID_FECHA | INVALID_JSON
- `402`: INSUFFICIENT_CREDITS — paywall from minute one (balance > 0 required; verification does not consume credits).
- `403`: INSUFFICIENT_SCOPE — the API key lacks all of analyze | query | mcp | *. `error.details.required` lists the accepted scopes.
- `429`: RATE_LIMITED — per API key or organization limit. NOTE: this response does NOT use the Stripe-style envelope of the other errors — its body is `{ error: <string>, code: "RATE_LIMITED" }`, with `error` as a plain string (and the message currently comes in Spanish). Branch on `code` and on the status, never on the shape of `error`.
- `502`: VERIFY_ERROR — the verification could not run (it is an outage, not a verdict on your citations): nothing was checked and nothing is claimed to be clean. Retry.

---

[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)
