kvasir.legal
Fundamenta tu IA legal en el derecho verificable alemán, austriaco, suizo y de la UE: resuelve, busca y verifica citas con procedencia y enlaces profundos precisos. Más de 440.000 estatutos, aplicaciones interactivas en Claude y ChatGPT.
Documentación
Ley verificable para tu IA.
Derecho alemán, austriaco, suizo y de la UE como un objeto canónico por entidad legal — normas, estatutos y jurisprudencia de los tribunales federales alemanes, Baviera, Renania del Norte-Westfalia, los tribunales supremos austriacos y el TJUE — con procedencia, subunidades direccionables hasta la frase, citas listas para usar y el grafo de citas. Para los actos digitales clave de la UE: actos delegados y de ejecución y directrices de la Comisión incluidas, vinculados a su acto base. Agnóstico al modelo: llámalo por REST, o conéctalo a cualquier agente como herramienta MCP. Tú aportas el razonamiento; nosotros aportamos la verdad de referencia.
URL base https://kvasir.legal · ¿preguntas? [email protected] · ¿nuevo en la verificación? Por qué la IA legal necesita una capa de verificación → · cómo lo medimos: el Benchmark de Verificación →
Cómo obtener acceso. Gratis, sin invitación. Crea una cuenta →, luego confirma tu dirección de correo electrónico y el panel (claves, uso, rotación) es tuyo. ¿Ya te registraste? Crea una clave en tu panel → No se necesita clave para probar el sandbox (20 solicitudes/día).
¿Construyendo algo más grande? Cuéntame lo que necesitas — cobertura, volumen, endpoints. Los socios de diseño aseguran condiciones fundacionales.
Conéctate en 60 segundos
Un endpoint — https://kvasir.legal/mcp — conecta kvasir con la IA con la que ya trabajas. Tu asistente entonces busca, resuelve y verifica citas contra el corpus en vivo en lugar de responder de memoria.
¿Solo quieres probarlo? https://kvasir.legal/mcp/demo — las mismas siete herramientas, sin clave, sin registro: 10 llamadas de herramientas por día e IP. Añádelo como conector personalizado (o claude mcp add --transport http kvasir-demo https://kvasir.legal/mcp/demo) y pide a tu asistente que revise un borrador. Usa el endpoint principal /mcp para trabajo real — lleva tu clave o inicio de sesión OAuth y tus propios límites.
ChatGPT. Configuración → Conectores → Avanzado → Modo desarrollador → añade servidor MCP https://kvasir.legal/mcp con cabecera X-API-Key → actívalo en las herramientas de tu chat.
Claude — sin necesidad de clave. Configuración → Conectores → Añadir conector personalizado → pega https://kvasir.legal/mcp → inicia sesión con tu cuenta de kvasir → listo. Las siete herramientas aparecen en cada chat.
Microsoft 365 Copilot. Disponible en toda la firma vía Copilot Studio: tu administrador de TI añade https://kvasir.legal/mcp una vez como acción MCP personalizada (clave API como X-API-Key) — cada abogado del inquilino puede usarlo en los chats de Copilot.
Perplexity. En planes con soporte de conectores: Configuración → Conectores → añade un conector MCP con URL https://kvasir.legal/mcp y tu X-API-Key.
Le Chat (Mistral). Configuración → Conectores → añade conector MCP → URL https://kvasir.legal/mcp + X-API-Key.
Herramientas de desarrollo y agentes. Cualquier cliente compatible con MCP habla con https://kvasir.legal/mcp (streamable-HTTP) con tu clave como X-API-Key — o usa REST simple (referencia interactiva).
Claude Code (un comando):
claude mcp add --transport http kvasir https://kvasir.legal/mcp --header "X-API-Key: kvk_…"
Claude Desktop (claude_desktop_config.json, vía mcp-remote):
{
"mcpServers": {
"kvasir": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://kvasir.legal/mcp",
"--header", "X-API-Key: kvk_…"]
}
}
}
Cursor / VS Code (.cursor/mcp.json · .vscode/mcp.json):
{
"mcpServers": {
"kvasir": {
"url": "https://kvasir.legal/mcp",
"headers": { "X-API-Key": "kvk_…" }
}
}
}
Autenticación
Pruébalo sin clave: resolve, search y object funcionan sin clave en modo sandbox — 20 solicitudes por día, sin registro. Solo llámalos:
curl --get "https://kvasir.legal/api/v1/resolve?include=none" --data-urlencode "cite=§ 573 Abs. 2 Nr. 2 BGB"
Para uso real, envía una clave API como cabecera (cualquiera de las dos formas funciona):
X-API-Key: kvk_your_key
Authorization: Bearer kvk_your_key
Las llamadas sin clave más allá del trío sandbox (o pasadas las 20 diarias) reciben 401 / 429 con una pista JSON. El contrato legible por máquina es público en /api/v1/schema (sin necesidad de clave).
¿Conectándote desde Claude u otro cliente MCP? Solo añade https://kvasir.legal/mcp como conector — se te guiará a través de un inicio de sesión OAuth con tu cuenta de kvasir en lugar de pegar una clave. Las claves y OAuth funcionan lado a lado; ambos cuentan contra el mismo nivel.
Ámbitos
Dos ámbitos, divididos por la única línea que importa — lo que tu cliente transmite:
| Ámbito | Qué permite |
|---|---|
legal.read | Todo excepto la verificación de borradores. Tu cliente envía cadenas de citas, URIs y consultas de búsqueda. Siempre concedido. |
legal.check | Añade check_draft / POST /api/v1/check-draft, que transmite el texto completo que envías. Concedido por separado. |
En el inicio de sesión OAuth decides con una casilla; el ámbito está vinculado a esa conexión y una renovación de token nunca lo amplía. Las claves API llevan ambos ámbitos por defecto — se puede emitir una clave restringida a legal.read bajo petición, y entonces la verificación de borradores se rechaza con 403 insufficient_scope en lugar de simplemente desaconsejarse. Así es como se puede aprovisionar un conector para que sea técnicamente incapaz de recibir documentos de clientes. Ver Confianza y Seguridad.
Inicio rápido
Sin clave, sin registro — esto funciona ahora mismo (sandbox, 20/día):
curl --get "https://kvasir.legal/api/v1/resolve?include=none" --data-urlencode "cite=§ 573 Abs. 2 Nr. 2 BGB"
Con una clave, obtén el objeto completo:
curl -H "X-API-Key: kvk_…" \
"https://kvasir.legal/api/v1/object/norm:bund:BGB:242?include=all"
{
"uri": "norm:bund:BGB:242",
"canonical_uri": "norm:bund:BGB:242",
"kind": "norm",
"exists": true,
"identity": { "title": "§ 242 BGB", "subtitle": "Bundesrecht", "href": "/bgb/242" },
"provenance": { "quelle": "bund", "source": "gesetze-im-internet.de", "derived": false, "version": "" },
"content": { "label": "§ 242", "plain_text": "Der Schuldner ist verpflichtet …", "html": "…" },
"units": [
{ "path": "a1", "unit": "abs", "label": "1",
"text": "…", "citation": "§ 242 Abs. 1 BGB", "deeplink": "/bgb/242#a1" }
],
"relations": { "in": [ … cited-by … ], "out": [ … cites … ] }
}
URIs de objetos
Cada objeto legal se direcciona con una URI estable:
| Tipo | URI | Ejemplo |
|---|---|---|
| Norma | norm:{quelle}:{kuerzel}:{norm_id} | norm:bund:BGB:242 · UE: norm:eu:GDPR:art_6 |
| Estatuto | gesetz:{quelle}:{kuerzel} | gesetz:bund:BGB · gesetz:eu:GDPR |
| Decisión | dec:{quelle}:{source_id|celex} | dec:eu:62018CJ0311 (Schrems II, C‑311/18) |
| Sección | section:{quelle}:{kuerzel}:{path_hash} | del children de un estatuto |
| Concepto | concept:{scheme}:{slug} | concept:eu:protection-of-personal-data |
| Versión de norma | normversion:{id} | normversion:1234 |
| Material | mat:{quelle}:{ident} | mat:eu:52022PC0454 |
quelle ∈ bund (federal), by (Baviera), nrw (Renania del Norte-Westfalia), sn (Sajonia), bb (Brandeburgo), hb (Bremen), at (Austria), ch (Suiza), eu. Las URIs de normas son tolerantes: norm:bund:BGB:242 resuelve el mismo objeto que el slug crudo; el canonical_uri de la respuesta da la forma limpia. Las normas de la UE usan identificadores art_N (norm:eu:GDPR:art_6, no …:6) — cuando no estés seguro, pasa por /api/v1/resolve, que devuelve la URI canónica. Los materiales son documentos legislativos, siempre vinculados a los actos y disposiciones que fundamentan, modifican o concretan. Para la UE: propuestas de la Comisión (con memorándum explicativo) y directrices de la Comisión (typ: "guideline" — interpretativas, no derecho vinculante). Para Alemania: proyectos de ley federales pendientes del DIP del Bundestag (typ: "vorhaben" — etapa procesal, texto del borrador y comandos de enmienda por disposición) y actos administrativos de BaFin (typ: "verfuegung"). Historial de redacción, interpretación oficial y una señal de alerta temprana para cambios pendientes.
Endpoints
¿Prefieres hacer clic? Prueba la referencia interactiva de API. ¿Construyendo con un LLM? Apúntalo a /llms.txt.
GET /api/v1/resolve?cite=§ 242 Abs. 1 BGB
Cita de entrada, objeto de salida. Analiza citas de texto libre (Art. 6 Abs. 1 lit. f DSGVO, C-311/18) — sin necesidad de gramática URI. Devuelve la subunidad de punto exacto y sugerencias de "quisiste decir" cuando algo no se resuelve.
Rangos. § 433 f. BGB y § 433 ff. BGB vuelven con un range, y los dos deliberadamente no se tratan igual. f. significa exactamente una disposición más, así que to es exacto — y sigue el orden propio del estatuto, donde § 311 f. BGB termina en § 311a, no en § 312. ff. es abierto: su final no está codificado en la cita, así que kvasir devuelve suggested_to (el final de la sección más interna alrededor de la primera disposición) y lo marca como una inferencia, nunca como un hallazgo. Lo que sí es demostrable es que algo sigue en absoluto — § 2385 ff. BGB produce range.valid: false, porque el BGB termina ahí y el "ff." no tiene a qué referirse.
Por debajo de la disposición, el marcador se vincula al nivel más profundo nombrado — § 305 Abs. 1 ff. BGB significa párrafos, § 573 Abs. 2 Nr. 1 ff. BGB significa números — y vuelve como unit_range. Allí incluso "ff." es exacto: la disposición limita su propia lista, así que § 305 con tres párrafos resuelve "Abs. 1 ff." a los párrafos 1–3, con cada unidad cubierta en paths. La apertura de arriba existe solo porque un estatuto continúa después del § 433; una disposición no.
Varias disposiciones en una cadena. §§ 433, 434 BGB, §§ 433-435 BGB, § 573 Abs. 1, 2 BGB y § 823 Abs. 1 i.V.m. § 1004 BGB nombran todas más de una disposición. Cada una se resuelve: la primera como objeto principal, el resto bajo also_cited con su propio exists. A qué nivel pertenece una continuación sigue el más profundo ya nombrado — , 2 después de Abs. 1 es un párrafo, después de § 433 una sección. El exists de nivel superior responde por toda la cita, así que un número inventado en la lista lo vuelve falso en lugar de pasar por la fuerza del primer acierto.
Variantes y jurisdicción. § 263 Abs. 1 Var. 2 StGB resuelve hasta el párrafo e informa variant.addressable: false: las Tatvarianten cuentan las alternativas dentro de la redacción de una disposición, pero el estatuto no las numera, así que no hay nada contra lo que verificar — kvasir lo dice en lugar de inventar un ancla. Por separado, &quellen=at restringe la jurisdicción, lo que importa para abreviaturas que existen más de una vez: § 15 StGB es derecho federal alemán por defecto y austriaco solo si lo pides. El filtro restringe en lugar de clasificar, así que sin acierto significa "no encontrado en esa jurisdicción".
Cuando una abreviatura encaja en dos jurisdicciones. BV es la constitución federal suiza y la bávara; Art. 141 existe en ambas — derecho de referéndum suizo aquí, el derecho a deambular por el campo abierto allí. Un resolvedor que solo elige la jurisdicción de mayor rango responde una pregunta que nunca se le hizo, y la responde invisiblemente. Así que cuando la misma abreviatura lleva el número citado en más de una jurisdicción, la respuesta añade ambiguous con cada candidato, y check_draft eleva ambiguous_jurisdiction. La resolución aún ocurre — el primer candidato por prioridad de jurisdicción — pero se etiqueta como una elección en lugar de un hallazgo. Pasa quellen para resolverlo.
Versiones. § 433 BGB a.F. pide un texto anterior al vigente. kvasir sirve derecho consolidado actual, así que la respuesta lleva version.confirmed: false: la cita está bien, el corpus simplemente no puede evidenciarla. Los textos superados existen solo desde la primera ejecución de indexación de kvasir y se fechan por detección, no por efecto legal — así que "qué versión estaba vigente el 1 de enero de 2020" es una pregunta que esta API no responde, y lo dice en lugar de devolver el texto de hoy como si fuera la respuesta. Los predecesores archivados, donde existen, se listan bajo superseded y son recuperables como normversion:<id>.
GET /api/v1/relations/<uri>?edge_type=zitiert_norm&limit=50
La jurisprudencia sobre una disposición. include=relations en un objeto da algunos ejemplos por tipo de borde más el total real — para el § 823 BGB ese total es 3,460. Este endpoint devuelve la lista en sí, paginada, para que puedas trabajar realmente con ella. direction=in (por defecto) es lo que cita esto, out lo que cita; la respuesta siempre incluye edge_types con conteos para que sepas sobre qué puedes filtrar.
Ordenado por autoridad (PageRank) — decisiones principales primero — con un desempate estable, para que la paginación nunca repita u omita una entrada. Esto importa aquí: la mayoría de los bordes comparten una puntuación de 0, y sin un orden total la misma decisión aparecería en dos páginas mientras otra nunca apareciera.
POST /api/v1/verify — { "citations": [ … ≤200 ] } o { "text": "…" }
La verificación de alucinaciones. Verifica cada cita en una respuesta redactada en una sola llamada: estado verified/unresolved por cita, URI canónica, fuente y unidad de punto exacto.
Un pinpoint forma parte de la afirmación: § 573 Abs. 6 BGB devuelve unresolved, porque esa disposición termina en el párrafo 4 — con norm_exists: true, unit_exists: false y un reason, de modo que un cliente puede distinguir "párrafo inventado en una disposición real" de "disposición inventada". Lo mismo aplica en /resolve: exists responde por el pinpoint citado, no meramente por la disposición en la que se encuentra, así que una compuerta que verifica una marca nunca recibe un párrafo inventado como válido. La disposición en sí sigue devolviéndose bajo object, marcada como norm_exists. Cuando la lista de párrafos no puede establecerse con certeza, la cita permanece verified y lleva unit_requested más una pista — kvasir no afirma una brecha que no puede probar.
POST /api/v1/check-draft — { "text": "…" }
La compuerta de fundamentación. Una sola llamada sobre un borrador completo, diseñada para ejecutarse antes de que una respuesta de IA se publique: verifica cada cita, comprueba citas textuales contra la redacción canónica de la fuente (similitud + extracto de la fuente en caso de desviación), y marca leyes derogadas y cambios legislativos pendientes en los actos citados. Devuelve summary.verdict (pass | warn | fail) más severidades por hallazgo.
GET /api/v1/object/<uri>?include=…
Un objeto. include está separado por comas; ver más abajo.
POST /api/v1/objects — { "uris": [ … ≤100 ], "include": "content" }
Resuelve por lotes muchas URIs en una sola llamada — por ejemplo, para fundamentar todas las citas de un borrador de una vez.
GET /api/v1/search?q=…&kinds=norm,decision&quellen=bund,by,eu&limit=20&offset=0
Búsqueda de texto libre → resultados clasificados [{uri, kind, title, snippet, score}]. Filtra por tipo (kinds: norm, decision, u opt-in material para materiales legislativos — propuestas de la UE y directrices de la Comisión, proyectos de ley federales alemanes y actos de BaFin, distinguidos por typ) y jurisdicción (quellen) para que cada posición de resultado cuente. Pagina mediante offset + has_more; los límites por fuente acotan el conjunto de resultados a aproximadamente 50 aciertos — refina la consulta en lugar de paginar en profundidad. Un campo degraded, cuando está presente, lista sub-búsquedas que fallaron: trata esos resultados como incompletos, no como ausencia.
GET /api/v1/changes?since=2026-07-01T00:00:00Z&kinds=norm,decision
Sincronización delta. Cada objeto modificado desde since, como URIs con marcas de tiempo. Continúa con el next_cursor de la respuesta (keyset — seguro ante reindexaciones masivas; también se proporciona next_since simple). Las filas pueden repetirse en los límites de página — mantén las operaciones de actualización del cliente idempotentes.
GET /api/v1/status — recuentos del corpus en vivo + frescura por jurisdicción (público, en caché).
Por fuente: *_updated (última escritura) vs. *_checked (última comprobación exitosa contra la fuente oficial, incluyendo ejecuciones que confirmaron que nada cambió), check_cadence y freshness por alcance. Más allá de norms y decisions, un objeto checks lleva los alcances restantes — notablemente repeal: cuándo se verificó por última vez que los actos de esta jurisdicción siguen en vigor. Para una compuerta de vigencia, ese es el alcance a observar; un texto reciente no dice nada sobre la validez continuada.
GET /api/v1/schema — el contrato, legible por máquina (público).
GET /api/v1/openapi.json — especificación OpenAPI 3.1 completa (pública). Impórtala en Postman o genera un SDK de cliente.
El parámetro quellen (filtro de jurisdicción)
Cada búsqueda acepta un filtro de jurisdicción — separado por comas, en /api/v1/search como quellen= (alias jurisdiction=) y en la herramienta MCP search_legal como quellen. El valor predeterminado son las nueve. Filtra en el servidor siempre que la pregunta sea específica de una jurisdicción: cada posición de resultado se gasta entonces donde realmente vive la respuesta, en lugar de verse desplazada por resultados federales alemanes. Un código desconocido devuelve 400 con la lista válida en lugar de ignorar silenciosamente el filtro.
| Código | Jurisdicción | Contiene |
|---|---|---|
bund | Alemania — federal | Leyes y reglamentos, decisiones de tribunales federales (BVerfG, BGH, BVerwG, BAG, BSG, BFH), materiales legislativos (proyectos de ley del Bundestag, actos de BaFin) |
by | Baviera | Derecho estatal, decisiones de tribunales bávaros |
nrw | Renania del Norte-Westfalia | Derecho estatal (SGV), jurisprudencia NRWE |
sn | Sajonia | Derecho estatal (REVOSAX) |
bb | Brandeburgo | Derecho estatal (BRAVORS) |
hb | Bremen | Derecho estatal |
at | Austria | Derecho federal (RIS), jurisprudencia OGH / VfGH / VwGH |
ch | Suiza | Derecho federal (Fedlex, SR) |
eu | Unión Europea | Reglamentos y directivas, jurisprudencia del TJUE, materiales legislativos |
GET /api/v1/search?q=Datenschutz&jurisdiction=at,ch&limit=5 → solo resultados austriacos y suizos. La respuesta refleja el filtro activo en su campo quellen, de modo que un cliente puede distinguir una búsqueda restringida de una completa.
El parámetro include
| Valor | Añade |
|---|---|
content | Texto completo + html + metadatos (predeterminado). |
none | Identidad, procedencia y (en /resolve) la unidad pinpoint — sin el texto completo. La llamada ligera de "¿existe, y dónde exactamente?". |
units | Sub-unidades direccionables con texto exacto, cita y enlace profundo — norma = párrafo/número/letra hasta la frase individual y la semifrase (a1.ba, a2.s1, a2.n3.h2), decisión = Randnummer (r17). Validado por fidelidad: solo se devuelven sub-unidades cuyo texto se verifica contra el texto completo; units_confidence informa la tasa de aprobación. |
versions | Redacciones anteriores de una norma como URIs normversion: (donde se rastreen). |
children | En una ley (gesetz:): la tabla de contenidos completa — cada norma como [{uri, label, section_path}] en orden. Pregunta "¿qué secciones tiene el BDSG?" en una sola llamada. |
relations | Grafo de citas: qué la cita / qué cita ella, instancias, conceptos — y en leyes la capa legislativa: para actos de la UE la propuesta fundacional de la Comisión (begruendet), propuestas de enmienda pendientes (aenderung_geplant), actos delegados/de ejecución (basiert_auf) y directrices de la Comisión (konkretisiert); para derecho federal alemán proyectos de ley del Bundestag pendientes con las disposiciones exactas que modificarían (aendert) y actos de BaFin (konkretisiert). Pregunta "¿qué cambios están planificados para el RGPD?" — o para el BGB — en una sola llamada. |
authority | Puntuación de autoridad estilo PageRank dentro del grafo. |
commentary | Comentario legal anclado y atribuido a autor sobre el objeto (nunca fusionado; cada entrada nombra su autor y nivel de anclaje). &commentary_scope=inherit añade los niveles envolventes (observaciones preliminares de sección, introducción de la ley). |
all | Todo lo anterior. |
Úsalo como herramienta MCP
Cada herramienta a continuación está documentada en su totalidad — parámetros, devoluciones, alcance requerido y cómo maneja los datos que envías — en la referencia de herramientas MCP.
Cualquier cliente MCP llama a la capa de forma nativa — endpoint https://kvasir.legal/mcp (OAuth o X-API-Key). Siete herramientas:
| Herramienta | Qué hace |
|---|---|
resolve_citation | Cadena de cita → objeto verificable + unidad pinpoint. El punto de entrada preferido. |
verify_citations | Verificación de alucinaciones por lotes (≤200) para una lista simple de citas. |
check_draft | La capa de verificación para un borrador completo: citas + redacción citada + marcas de derogado/cambio pendiente → pass | warn | fail. |
search_legal | Búsqueda semántica + de texto completo → URIs canónicas clasificadas. |
get_legal_relations | Pagina el grafo de citas desde una URI — cada decisión que cita una disposición, ordenada por autoridad. |
get_legal_object | Una URI → objeto con procedencia, unidades, versiones, relaciones. |
get_legal_objects | Resolución por lotes (≤100 URIs). |
legal_uri_grammar | Referencia del esquema de URIs para construir URIs. |
Límites de tasa y errores
Los errores son JSON: { "error", "hint", "docs_url" } (los 429 también llevan un code: rate_limited | quota_exceeded | sandbox_limit). 401 = clave faltante/inválida · 429 = límite alcanzado · 503 = breve contratiempo de infraestructura (tu clave está bien — reintenta) · exists:false significa que la URI no coincidió con nada (no es un error del servidor).
Valores predeterminados: 120 solicitudes/min y 50,000/mes por clave (socios de diseño: cuéntanos qué necesitas). Cada respuesta lleva X-RateLimit-Limit / -Remaining / -Reset; los 429 añaden Retry-After. Las respuestas de sandbox llevan X-Sandbox-Remaining.