Lexistoria oferă abonaților Max acces programatic la legislația României: un API REST și un server MCP (Model Context Protocol) pentru asistenți AI. Ambele servesc aceleași răspunsuri, cu aceleași reguli de onestitate ca site-ul: textul consolidat la zi sau la orice dată din istoric, cu citări canonice și cu stările reale ale evidenței spuse explicit.
Principii
- Răspunsuri în formă de întrebare. Fiecare răspuns e legat de o citare concretă — un act, un articol, o dată — și e mărginit. Nu există endpoint-uri de export în masă.
- Onestitate temporală. La o dată din trecut, răspunsul poate fi legitim „nu exista încă”, „istoricul e în verificare” sau „actul era abrogat” — stări explicite în răspuns (vezi Stările oneste), niciodată textul de azi prezentat drept forma de atunci.
- Adresare identică cu site-ul. Slug-urile și parametrul
la=sunt aceleași ca în URL-urile paginilor — un răspuns API și o pagină citează la fel.
Autentificare
Toate cererile poartă o cheie de API în antetul Authorization:
Authorization: Bearer lxk_...
Cheile se emit pentru conturile cu planul Max, din pagina contului. Cheia se afișează o singură dată la emitere și moștenește planul contului la fiecare cerere: un abonament expirat răspunde imediat cu 403. Autentificarea se face exclusiv prin antet — sesiunea de browser nu deschide API-ul, iar API-ul nu poate fi apelat din JavaScript-ul altor site-uri.
Limite
| Limita | Valoarea | La depășire |
|---|---|---|
| Cotă zilnică (per cheie, zi UTC) | 5.000 de cereri | 429 quota_exceeded + Retry-After |
| Rafală (per cheie) | 60 de cereri / minut | 429 rate_limited + Retry-After |
| Rezultate de căutare | toate, paginate cu cursor — implicit 25 pe pagină, maximum 100 | plafonat automat |
| Snippet per rezultat | implicit 300 de caractere, maximum 2000; text=integral include textul complet | plafonat automat |
Un apel de tool MCP contează ca o cerere. Erorile au forma { "error": "...", "message": "..." } cu status HTTP corect.
API REST — /api/v1
Baza: https://www.lexistoria.ro/api/v1. Toate răspunsurile sunt JSON, UTF-8. Parametrul la=AAAA-LL-ZZ cere forma legii la acea dată, oriunde apare.
| Endpoint | Răspunsul |
|---|---|
GET /acte | Catalogul: identitățile legale (slug, tip, număr/an, titlu), starea (în vigoare / abrogat) și filiația între generații (succeeded_by, predecessors — ex. Codul silvic 2008 → Codul silvic). Punctul de plecare. |
GET /act/{slug} | Un act la o dată: identitate, filiație, un nivel de cuprins (coboară cu ?nod={id}, lazy ca pe site) și lista anexelor. Parametri: la, nod. |
GET /act/{slug}/articol/{artSlug} | Un articol la o dată: textul, arborele de segmente (alineate / litere / puncte), numele marginal și faptele versiunii servite — felul modificării, intervalul de valabilitate, actul modificator unde e atestat. Parametru: la. |
GET /act/{slug}/articol/{artSlug}/istoric | Istoricul articolului: evenimentele lui (dată, fel, actul modificator) și evenimentele pe elemente, pe chei canonice (alin:2, alin:2/lit:b). |
GET /act/{slug}/anexa/{anexa} | O anexă la o dată: conținutul și faptele versiunii, inclusiv stub-ul de abrogare în loc și anexa care nu mai face parte din act. Parametru: la. |
GET /act/{slug}/modificari | Changelogul actului între două date: fiecare eveniment datat pe articole și anexe, cu felul schimbării, citarea actului modificator unde e atestată și URL-ul formei rezultate. Parametri: de_la, pana_la (opționale), cursor, pe_pagina. |
GET /act/{slug}/articol/{artSlug}/diff | Două forme datate ale unui articol, comparate pe server, pe elemente canonice: adăugat / eliminat / modificat, cu ambele texte per element. Parametri: de_la, pana_la (ambele obligatorii). Capete absente sau reținute onest răspund cu stările lor, nu cu texte inventate. |
GET /act/{slug}/cuprins | Cuprinsul complet la o dată — toată structura cu numerele și denumirile de atunci, toate articolele (cu URL citabil) și anexele, într-un singur răspuns. Fiecare nod poartă marime_text (caracterele subarborelui). Parametru: la. |
GET /act/{slug}/sectiune/{nod} | O subdiviziune întreagă la o dată: titlurile interioare și articolele cu textul complet, în ordinea documentului, plus crumb-ul. Id-ul nodului vine din cuprins. Paginat doar peste bugetul tehnic de caractere. Parametri: la, cursor. |
GET /act/{slug}/text | Textul integral al actului la o dată, în ordinea documentului: blocuri titlu / articol / anexa (stub), fiecare cu adresa lui citabilă; paginat cu cursor pe un buget de caractere. Parametri: la, cursor. |
GET /cauta?q= | Căutarea în legislație — în legea de azi sau, cu la=AAAA-LL-ZZ, în legea așa cum era la acea dată (versiunile în vigoare atunci, doar în actele care erau lege atunci). Ordine de relevanță; toate rezultatele, paginate: răspunsul poartă cursor_urmator, retrimis ca cursor. Parametri: pe_pagina, snippet (caractere), text=integral (textul complet al fiecărui rezultat). Fără la, formele curente includ și formele finale ale actelor abrogate — act.status spune starea. Textele reținute onest (istoric în verificare) nu sunt căutabile. |
GET /trimiteri?act= | Trimiterile inverse: articolele din tot corpusul care menționează actul-țintă (identitatea numerică, ex. 53/2003), opțional și un articol anume. Onest-euristic — mențiuni textuale, nu graf semantic. Parametri: articol, la, cursor, pe_pagina. |
GET /definitii?termen= | Definițiile legale ale unui termen: segmentele-definiție servite întregi, din articolele cu formă definițională, în tot corpusul sau într-un act (act), la o dată. formula spune dacă segmentul chiar leagă termenul de o formulă definițională. Parametri: act, la, cursor, pe_pagina. |
GET /citare?text= | Rezolvă o citare naturală („art. 16 alin. (1) din Codul muncii”) la adrese canonice — determinist, cu elementele (alineat / literă / punct) recunoscute și returnate structurat. recognized: false = textul nu e o citare; matches gol = nu există în corpus. |
Exemple
Articolul 16 din Codul muncii, în forma de azi:
curl https://www.lexistoria.ro/api/v1/act/codul-muncii/articol/art-16 \ -H "Authorization: Bearer lxk_..."
Același articol, în forma din 1 ianuarie 2012:
curl "https://www.lexistoria.ro/api/v1/act/codul-muncii/articol/art-16?la=2012-01-01" \ -H "Authorization: Bearer lxk_..."
Răspunsul (scurtat):
{
"act": { "slug": "codul-muncii", "name": "Codul muncii" },
"articol": {
"slug": "art-16",
"article_number": "16",
"la": "2012-01-01",
"absent_at_date": false,
"history_held": false,
"text": "Contractul individual de muncă se încheie ...",
"segments": [ { "type": "alineat", "label": "(1)", "text": "...", "children": [] } ],
"version": {
"change_type": "republicare",
"effective_from": "2011-05-18",
"effective_until": "2018-04-13",
"citation": null
}
}
}O citare rezolvată:
curl "https://www.lexistoria.ro/api/v1/citare?text=art.%2028%20og%202/2001" \ -H "Authorization: Bearer lxk_..."
Stările oneste
Distincția de bază: 404 înseamnă că identitatea nu există deloc; 200 cu indicatori înseamnă că există, dar nu la data cerută — clientul trebuie să le deosebească.
| Indicator | Înseamnă | Exemplu real |
|---|---|---|
absent_at_date: true | Nu exista la data cerută; pe acte, reason gradează certitudinea, iar predecessor_at_date indică generația care era atunci în vigoare. | /act/codul-silvic?la=2020-06-01 → puntea către Codul silvic (2008) |
history_held: true | Istoricul acelui element e încă în verificare la data cerută — textul nu se servește (niciodată textul de azi sub o dată din trecut). | /act/codul-fiscal/articol/art-7?la=2019-06-01 |
gone: true | Actul era abrogat la data cerută; succeeded_by indică succesorul, de deschis la aceeași dată. | /act/codul-silvic-2008?la=2026-01-01 |
Serverul MCP
Endpoint: https://www.lexistoria.ro/mcp — transport streamable HTTP, fără sesiuni, cu aceeași cheie în același antet. Tool-urile corespund 1:1 endpoint-urilor REST și întorc aceleași forme JSON:
| Tool | Endpoint-ul pereche |
|---|---|
lexistoria_acte | /acte |
lexistoria_act | /act/{slug} |
lexistoria_articol | /act/{slug}/articol/{artSlug} |
lexistoria_istoric | …/istoric |
lexistoria_anexa | /act/{slug}/anexa/{anexa} |
lexistoria_modificari | /act/{slug}/modificari |
lexistoria_diff | /act/{slug}/articol/{artSlug}/diff |
lexistoria_cuprins | /act/{slug}/cuprins |
lexistoria_sectiune | /act/{slug}/sectiune/{nod} |
lexistoria_text | /act/{slug}/text |
lexistoria_cauta | /cauta |
lexistoria_trimiteri | /trimiteri |
lexistoria_definitii | /definitii |
lexistoria_citare | /citare |
În Claude Code:
claude mcp add --transport http lexistoria https://www.lexistoria.ro/mcp \ --header "Authorization: Bearer lxk_..."
În orice client MCP care suportă servere remote cu antete personalizate (configurație generică):
{
"mcpServers": {
"lexistoria": {
"type": "http",
"url": "https://www.lexistoria.ro/mcp",
"headers": { "Authorization": "Bearer lxk_..." }
}
}
}Descrierile tool-urilor învață asistentul gramatica citărilor și stările oneste, așa că un agent conectat va spune „articolul nu exista la această dată” în loc să inventeze — exact comportamentul site-ului.
Versionare și stabilitate
Formele răspunsurilor din /api/v1 sunt înghețate: câmpuri noi pot apărea (aditiv), câmpurile existente nu se schimbă și nu dispar. O schimbare incompatibilă ar deschide /v2, cu /v1 păstrat în paralel.
Erori
| Status | error | Când |
|---|---|---|
| 400 | bad_request | parametru invalid (ex. la care nu e dată ISO) |
| 401 | unauthorized | cheie lipsă, invalidă sau revocată |
| 403 | forbidden | planul contului nu include accesul API |
| 404 | not_found | identitate inexistentă (act, articol, anexă) |
| 429 | rate_limited / quota_exceeded | rafală / cota zilnică — reia după Retry-After |
Acces în planul Max · texte cu caracter informativ, conform termenilor.