kvasir.legal
將您的法律AI建立在可驗證的德國、奧地利、瑞士及歐盟法律之上——解析、搜尋並驗證引用,提供來源出處與精確深層連結。超過44萬條法規,支援Claude與ChatGPT中的互動應用。
文件
kvasir API
Read-only access to German, Austrian, Swiss and EU law. Resolve a citation, check a draft against the official wording, search, and walk the citation graph. Every object carries its source, its version and a pinpoint down to the sentence.
| Base URL | https://kvasir.legal/api/v1 |
|---|---|
| MCP | https://kvasir.legal/mcp · setup & tools |
| Auth | API key or OAuth. Six read endpoints also work without a key (20 calls a day per IP). |
| Format | JSON over HTTPS. No SDK needed. |
Try it now, no key needed:
curl --get https://kvasir.legal/api/v1/resolve \
--data-urlencode "cite=§ 573 Abs. 2 Nr. 2 BGB" -d include=none
import requests
r = requests.get("https://kvasir.legal/api/v1/resolve",
params={"cite": "§ 573 Abs. 2 Nr. 2 BGB", "include": "none"})
print(r.json()["exists"], r.json()["uri"])
const url = new URL("https://kvasir.legal/api/v1/resolve");
url.search = new URLSearchParams({ cite: "§ 573 Abs. 2 Nr. 2 BGB", include: "none" });
const obj = await (await fetch(url)).json();
console.log(obj.exists, obj.uri);
Authentication
Create an account, confirm your email and issue a key in the dashboard. Send it in either header:
X-API-Key: kvk_…
Authorization: Bearer kvk_…
Without a key, /resolve, /search, /object, /relations, /verify and /check-draft (up to 5,000 characters) answer in sandbox mode: 20 calls a day per IP, marked with X-Sandbox: true.
MCP clients sign in with OAuth instead of a key. Keys and OAuth count against the same plan.
Scopes
| Scope | Allows |
|---|---|
legal.read | Everything except draft checking. Always granted. |
legal.check | /check-draft and check_draft, the only calls that receive a full document. Can be withheld per key or connection. |
workspace | The user's own collections and notes (MCP, OAuth only). Opt-in at sign-in. |
A key limited to legal.read gets 403 insufficient_scope on draft checking, so a connector can be provisioned that cannot receive client documents at all. More on Trust & security.
Limits & errors
60 requests per minute per key on Single, 600 on Team. Monthly volume counts in sips: 1 per lookup, 2 per search or relations page, 5 per check-draft, batches per item. Single includes 2,000 sips a month; Team allowances are agreed per contract. Usage is in your dashboard.
| Status | Meaning |
|---|---|
400 | Bad parameter, e.g. an unknown jurisdiction code. The body lists the valid values. |
401 | Missing or invalid key. |
403 | Key lacks the scope (insufficient_scope). |
429 | Limit reached: rate_limited, quota_exceeded or sandbox_limit. Honour Retry-After. |
503 | Brief infrastructure hiccup. Retry. |
Errors are JSON: { "error", "hint", "docs_url" }. Responses carry X-RateLimit-Limit, -Remaining and -Reset (keyless: X-Sandbox-Remaining). exists: false is not an error: the citation or URI matched nothing in the corpus.
Resolve a citation
GET /api/v1/resolve
Citation string in, canonical object out. Handles free text like Art. 6 Abs. 1 lit. f DSGVO, § 1295 ABGB, C-311/18, and returns the pinpoint unit plus did-you-mean suggestions when nothing matches.
| Parameter | Description |
|---|---|
cite required | The citation. |
include | What to return, see include. Default content. |
quellen | Restrict to jurisdictions, see Jurisdictions. |
lang | de: German wording for EU acts, fetched live from EUR-Lex. |
exists answers for the cited pinpoint: § 573 Abs. 6 BGB is false with norm_exists: true, unit_exists: false and a reason, because § 573 ends at paragraph 4.
How special citations resolve
Ranges: f. and ff.
Return a range. f. is exact and follows the statute's order (§ 311 f. BGB ends at § 311a). ff. is open: suggested_to is marked as an inference. If nothing follows at all, range.valid is false. Below a provision (§ 305 Abs. 1 ff.) the range is exact and comes back as unit_range.
Several provisions
§§ 433, 434 BGB, § 823 Abs. 1 i.V.m. § 1004 BGB: the first is the main object, the rest are in also_cited. Top-level exists is false if any is invented.
Same abbreviation in two jurisdictions
Art. 141 BV exists in Switzerland and Bavaria. The answer carries ambiguous with every candidate. Pass quellen to settle it.
Artikel and Paragraphen
In Art. 246a § 1 EGBGB the § is part of the address. Citing the wrong divider still resolves but adds a marker_note.
Variants and old versions
Var. 2 resolves to the paragraph with variant.addressable: false. a.F. returns version.confirmed: false: the corpus holds current law and says so.
EU acts in German
The EU corpus is English. lang=de returns the equally authentic German text; content.language always states which one you got.
Verify citations
POST /api/v1/verify
Checks up to 200 citations in one call. Per citation: verified or unresolved, canonical URI, source and pinpoint.
{ "citations": ["§ 242 BGB", "Art. 6 DSGVO"], "quellen": "bund,eu" }
// or: { "text": "…" } to extract the citations first
Check a draft
POST /api/v1/check-draft
One call over a full draft: verifies every citation, compares quoted wording with the official text, and flags repealed law and pending amendments. Returns summary.verdict (pass | warn | fail) and findings with severities. Deterministic, no language model involved, nothing stored.
curl https://kvasir.legal/api/v1/check-draft \
-H "X-API-Key: kvk_…" -H "Content-Type: application/json" \
-d '{"text": "Nach § 573 Abs. 2 Nr. 2 BGB …", "quellen": "bund"}'
r = requests.post("https://kvasir.legal/api/v1/check-draft",
headers={"X-API-Key": "kvk_…"},
json={"text": draft, "quellen": "bund"})
print(r.json()["summary"]["verdict"])
Search
GET /api/v1/search
Semantic and full-text search, ranked: [{uri, kind, title, snippet, score}].
| Parameter | Description |
|---|---|
q required | Question or keywords. |
kinds | norm, decision, material (opt-in). Comma-separated. |
quellen | Jurisdictions (alias jurisdiction). |
limit, offset | Paging. limit default 20, max 50. Refine the query rather than paging deep. |
If part of the search failed, the response has a degraded field. Treat those results as incomplete, not as absence.
Get an object
GET /api/v1/object/<uri>
One object by URI, with include and lang as on /resolve.
{
"uri": "norm:bund:BGB:242",
"kind": "norm",
"exists": true,
"identity": { "title": "§ 242 BGB", "href": "/bgb/242" },
"provenance": { "source": "gesetze-im-internet.de", "version": "<hash>" },
"content": { "plain_text": "Der Schuldner ist verpflichtet …" },
"units": [ { "path": "a1", "citation": "§ 242 Abs. 1 BGB", "text": "…" } ]
}
Get many objects
POST /api/v1/objects
Up to 100 URIs in one call: { "uris": [ … ], "include": "content" }.
Citation graph
GET /api/v1/relations/<uri>
Everything that cites an object (or that it cites), paged and ordered by authority, leading decisions first.
| Parameter | Description |
|---|---|
direction | in (default): what cites this. out: what this cites. |
edge_type | e.g. zitiert_norm. The response lists all types with counts. |
limit, offset | Paging. Default 50, max 200. Stable order, no repeats. |
Changes
GET /api/v1/changes
Delta sync: every object changed since since (ISO timestamp), as URIs with timestamps. kinds defaults to norm,decision, limit to 500. Continue with cursor from next_cursor. Rows can repeat at page boundaries, so keep upserts idempotent.
Corpus status
GET /api/v1/status
Public. Counts and freshness per jurisdiction: *_updated (last change) and *_checked (last check against the official source, even when nothing changed), plus check_cadence. For a currency gate watch checks.repeal. Human view: Status, Sources.
MCP server
The same corpus as the REST API, as tools for Claude, ChatGPT, Copilot and any other MCP client. One endpoint, streamable HTTP, OAuth or API key.
| Endpoint | https://kvasir.legal/mcp |
|---|---|
| Try without account | https://kvasir.legal/mcp/demo · 10 tool calls a day per IP |
| Auth | OAuth sign-in, or header X-API-Key: kvk_… |
Connect
| Claude | Settings → Connectors → Add custom connector → paste the endpoint → sign in. |
|---|---|
| ChatGPT | Settings → Apps & Connectors → Advanced → Developer mode → Create → endpoint, OAuth. In Business and Enterprise an admin enables it. |
| Microsoft 365 Copilot | IT adds the endpoint once in Copilot Studio as a custom MCP action (key as X-API-Key). Then available tenant-wide. |
| Legora | Workspace admin adds the endpoint as a custom MCP server (OAuth or key). |
| Perplexity · Le Chat | Settings → Connectors → add MCP connector with the endpoint and X-API-Key. |
Developer tools:
claude mcp add --transport http kvasir https://kvasir.legal/mcp \
--header "X-API-Key: kvk_…"
// .cursor/mcp.json · .vscode/mcp.json
{
"mcpServers": {
"kvasir": {
"url": "https://kvasir.legal/mcp",
"headers": { "X-API-Key": "kvk_…" }
}
}
}
// claude_desktop_config.json, via mcp-remote
{
"mcpServers": {
"kvasir": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://kvasir.legal/mcp",
"--header", "X-API-Key: kvk_…"]
}
}
}
Tools
Eight tools read the corpus. Six more work with the user's own collections and notes in the kvasir app; they need the workspace scope, which only an OAuth sign-in can grant.
Corpus
resolve_citation legal.read
Citation string → canonical provision with pinpoint, or explicit findings when the citation is wrong. The usual entry point. REST: /resolve.
cite required | § 242 Abs. 1 BGB, Art. 6 DSGVO, C-311/18 |
|---|---|
include, quellen | As in the REST API |
Data: the citation string, used for the lookup and discarded.
verify_citations legal.read
Up to 200 citations at once: verified, unresolved or unparsed, with the reason when a real provision is cited wrongly.
citations required | List of citation strings |
|---|---|
quellen | Jurisdiction filter |
Data: citation strings only, not stored.
check_draft legal.check
A full draft: every citation, every quoted passage against the official wording, repealed law and pending amendments, plus a verdict.
text required | The draft, no markup needed |
|---|---|
quellen | Jurisdiction filter |
Data: the only tool that receives a full document. Processed entirely on kvasir's own servers by pattern matching, database lookups and local string comparison. No language model, no third party, nothing written to disk. Behind its own scope so it can be withheld.
search_legal legal.read
Provisions, decisions and materials by topic. Reports degraded if part of the search failed.
query required | Question or topic |
|---|---|
kinds, quellen, limit, offset | As in the REST API |
Data: the query is sent to Mistral to compute an embedding. The only egress of user text in the whole tool set. The vector is cached 24 h under a hash of the query; the query itself is not stored.
get_legal_object · get_legal_objects legal.read
One object by URI, or up to 100 in one call, with wording, provenance, citation string and deeplink.
uri / uris required | norm:bund:BGB:242, dec:eu:62018CJ0311, gesetz:eu:GDPR |
|---|---|
include, commentary_scope | As in the REST API |
Data: URIs, not stored.
get_legal_relations legal.read
The citation graph from one object, paged by authority, e.g. every decision citing a provision.
uri required | Start object |
|---|---|
direction, edge_type, limit, offset | As in the REST API |
Data: a URI, not stored.
legal_uri_grammar legal.read
The URI scheme and jurisdiction codes, so URIs can be built instead of guessed. No parameters.
Collections and notes
list_collections · get_collection workspace
The user's folders and those shared with them; one folder's items, with include="content" also the texts of up to 50 items as working context.
collection | Name or id (get_collection) |
|---|---|
include | content to add the texts |
add_to_collection · remove_from_collection workspace
Adds or removes items by URI. Adding creates the folder if needed. Removing only takes the item out of the folder. Deleting folders stays in the app.
collection required | Name or id |
|---|---|
uris required | Canonical URIs |
create_if_missing | Default true (add only) |
list_notes · add_note workspace
Searches the user's notes on provisions, including notes colleagues shared with their team, or attaches a new one to a passage. The quote must match the provision's current text verbatim, otherwise the note is rejected.
query, law, limit | Filters (list_notes) |
|---|---|
uri, quote, body | Provision, exact passage, note (add_note) |
share_with_team | Make the note visible to the user's team (Team accounts only) |
Data: these six tools read the signed-in user's own collections and notes and those their team shared with the team; they write only the user's own. API keys and the demo endpoint have no access to them.
Data handling
| Stored | Usage metering only: key, date, tool name, call count. Never queries, citations or drafts. |
|---|---|
| Third parties | One: search_legal sends the query to Mistral for an embedding. |
| Writes | Only the six workspace tools, and only in the user's own collections and notes. Nothing writes to the legal corpus. |
| Scopes | legal.read for retrieval, legal.check for check_draft, workspace for collections and notes. |
| Freshness | Statutes and case law are checked daily; per-source state on Sources. |
Security review details: Trust & security.
Object URIs
| Kind | Pattern | Example |
|---|---|---|
| Provision | norm:{quelle}:{kuerzel}:{id} | norm:bund:BGB:242, norm:eu:GDPR:art_6 |
| Statute | gesetz:{quelle}:{kuerzel} | gesetz:bund:BGB |
| Decision | dec:{quelle}:{id} | dec:eu:62018CJ0311 (Schrems II) |
| Material | mat:{quelle}:{id} | mat:eu:52022PC0454 |
| Section | section:{quelle}:{kuerzel}:{hash} | from a statute's children |
| Concept | concept:{scheme}:{slug} | concept:eu:protection-of-personal-data |
| Old version | normversion:{id} | from include=versions |
Unsure about an id? Go through /resolve; it returns canonical_uri. Materials are EU proposals and Commission guidelines (typ: guideline, not binding law), German federal bills (typ: vorhaben) and BaFin acts.
Jurisdictions
quellen restricts every call that has to choose a provision: a query parameter on /search and /resolve, a body field on /verify and /check-draft, an argument on the MCP tools. It filters, it does not rank, and the response echoes it. Set it whenever you know the jurisdiction: it turns an ambiguous warning into an answer.
| Code | Jurisdiction | Contains |
|---|---|---|
bund | Germany, federal | Statutes, federal courts, Bundestag bills, BaFin acts |
by | Bavaria | State law, Bavarian courts |
nrw | North Rhine-Westphalia | State law, NRW courts |
sn · bb · hb | Saxony · Brandenburg · Bremen | State law |
at | Austria | Federal and Länder law (region, e.g. at-wien), OGH, VfGH, VwGH |
ch | Switzerland | Federal law |
eu | European Union | Regulations, directives, CJEU, legislative materials |
include
Comma-separated on /resolve, /object and /objects.
| Value | Returns |
|---|---|
content | Full text, HTML and metadata. Default. |
none | Identity, provenance and pinpoint only. The light "does it exist?" call. |
units | Addressable sub-units down to the sentence (a1, a2.s1, a2.n3.h2) or Randnummer (r17), each with text, citation and deeplink. |
children | On a statute: its table of contents. |
relations | Citation graph samples with totals, and on statutes the legislative layer: founding proposal, pending amendments, delegated acts, guidelines. |
versions | Earlier wordings as normversion: URIs. |
authority | Authority score in the citation graph. |
commentary | Author-attributed commentary anchored to the object. |
all | All of the above. |
Need more volume, coverage or an endpoint that does not exist yet? [email protected]