# Monitorul Oficial al României > Every act the Portal Legislativ of the Romanian Ministry of Justice holds from Monitorul Oficial al României, with its complete text — laws, ordinances, emergency ordinances, government decisions, decrees, ministerial orders and Constitutional Court decisions. One row is one Portal Legislativ document — the portal's own record of an act — and that is the grain, deliberately: nothing in the source establishes that the portal holds every act ever published in Partea I, and a document whose gazette citation cannot be parsed out of its text still lands here, with a null mo_date. Coverage is Partea I (the acts of general application), a smaller pool of Partea a V-a records, and, for the period before 1989, the predecessor Buletinul Oficial; the corpus reaches back to the 1830s. Parts II, III, IV, VI and VII are NOT covered — no parliamentary debates, no company or association announcements, no public procurement notices. One caveat about completeness: the source paginates without a stable server-side sort and publishes no total count, so a single crawl both returns some acts twice and can miss others entirely. The repeats are collapsed on document_id before publication; the omissions are filled in by later runs, because acts are upserted — completeness here is approached run after run, never guaranteed by any one of them. The acts that do arrive are complete and correct in themselves: the risk is coverage, not corruption. - Dataset id: `monitorul-oficial` - Update cadence: daily - Upstream source: https://legislatie.just.ro/ - Tags: romania, legislation, official-gazette, monitorul-oficial, law, legal, acts, government - Current version: ingest `01M5423ZBM0YYV1R4HMX4TERH0`, snapshot 2026-10-17, generated 2026-10-17T04:54:03.650Z ## Licence and attribution - Licence: Romanian official texts — outside copyright (Legea nr. 8/1996 art. 9 lit. b), reused under the Portal Legislativ terms (`ro-official-texts-public`) - Licence text: https://legislatie.just.ro/Public/Termeni - Required attribution: Text acts from the Portal Legislativ of the Romanian Ministry of Justice (legislatie.just.ro). Official source: Monitorul Oficial al României. - Notes: THE BASIS. Two things permit this dataset, and they are sufficient on their own. First, the texts are not protected material: Legea nr. 8/1996 privind dreptul de autor, art. 9 lit. b), excludes "textele oficiale de natură politică, legislativă, administrativă, judiciară și traducerile oficiale ale acestora" from copyright protection, so the acts themselves carry no author's rights a reuser could infringe. Second, the publisher these bytes actually come from permits reuse: the Portal Legislativ's terms page (https://legislatie.just.ro/Public/Termeni) states that "este posibila reutilizarea textelor legale in limita celor prezentate mai sus" — reuse of the legal texts is possible WITHIN THE LIMITS SET OUT ABOVE on that page. The qualifier is quoted here because it is part of the sentence: the permission is granted subject to the rest of that page, not unconditionally, and the caveats below are those limits as they apply to a republished copy. CONTEXT, NOT THE BASIS. Legea nr. 202/1998 privind organizarea Monitorului Oficial al României, art. 18 alin. (2), as amended by Legea nr. 57/2021, makes the electronic edition of Parts I and II "disponibil în mod gratuit și liber, permanent… inclusiv pentru căutare, salvare, distribuire și imprimare" — free and permanent access that names distribution and saving explicitly. That grant is real, but it attaches to the PDF edition published by Regia Autonomă Monitorul Oficial on monitoruloficial.ro, and this dataset does not use that edition at all. It is recorded here only so a reader knows the underlying material is freely redistributable by statute as well as unprotected by copyright; nothing here rests on it. WHERE THE BYTES COME FROM, AND WHY NOT THE GAZETTE ITSELF. Every row here was fetched from the Ministry of Justice's Portal Legislativ (legislatie.just.ro), not from monitoruloficial.ro, the gazette's own publisher — even though that is the obvious source and the attribution line names Monitorul Oficial al României as the official source, which it is, because that is where these acts were legally published. monitoruloficial.ro is deliberately not used for four reasons: its robots.txt disallows /ramo_customs/, where every one of its data endpoints lives, and /docs/, where the PDFs live, so it offers no permitted machine route to its data; its free electronic edition begins at 2000 (Partea I in Hungarian at 2008) and everything earlier is a paid archive ordered by email; it serves PDFs, many of them scans, rather than text; and it was unreachable throughout this connector's development, with TLS connections reset at the edge. WHAT WAS CHECKED ON THE SOURCE ACTUALLY USED. https://legislatie.just.ro/robots.txt returns a 302 to /Error — there is no robots.txt on that host at all. That is not a prohibition, and it is not permission either; it is recorded because the checklist requires the file to have been looked at. The endpoint this connector calls, /apiws/FreeWebService.svc, is an undocumented public read-only SOAP service whose WSDL is its only published contract: no documentation, no published rate limits, no quota headers. That is precisely why the connector paces itself, at a conservative default of one Search request per second (--param delayMs, in milliseconds), rather than discovering the service's real limit by hitting it. CAVEATS A REUSER MUST READ BEFORE CITING ANYTHING HERE. First, authority: only the text printed and published in Monitorul Oficial is legally authoritative, and where an electronic version differs from the printed one, the printed one governs. This dataset is informational and must not be cited as the legal text of record — check the printed gazette, or the portal record it links to, before relying on a wording in court, in a contract or in an official document. Second, consolidation: the portal describes its consolidated forms of an act as a "reproducere neoficială" carrying no citation value, and instructs in the same breath that "La astfel de acte nu se va face nicio referire în nici un document oficial" — no reference to such texts is to be made in any official document. A consolidated text here shows the state of an act as the portal understands it, not an official republication, and the portal itself says not to cite it officially. What this dataset publishes is act metadata plus the plain text exactly as the portal serves it — no re-editing, no re-interpretation. Coverage is Partea I plus a smaller Partea a V-a pool, and Buletinul Oficial for the pre-1989 period; Parts II, III, IV, VI and VII of the gazette are not covered at all. A third caveat, this one about completeness rather than permission, and it is a property of the source rather than of this connector: the portal's Search operation paginates without a stable server-side sort, so records shift position between one page request and the next. A single crawl therefore returns some acts more than once — sampling eight consecutive pages of one year returned 80 records carrying only 70 distinct document ids — and, by exactly the same mechanism, can push an act past a page the crawl has already read, so that it is never returned at all. The service exposes no total-count field, so a run cannot verify its own completeness. Repeats are collapsed on document_id before anything is published — the crawl keeps the first copy of each act it sees across the run, favouring the longest text only among copies that land on the very same page; omissions are invisible from inside a run and are instead filled in over time, because acts are upserted and every later run can supply what an earlier one missed. Treat completeness here as something approached by repeated runs, not as a guarantee made by any single one — and note the limit of the problem: the acts that are returned are complete and correct in themselves, so the risk is coverage, never corruption. Reproduce the attribution line verbatim anywhere you republish this data. ## Manifest - Start here for how this directory works: https://data.bunnytech.app/llms.txt - This dataset: https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/manifest.json - All datasets: https://data-directory.fsn1.your-objectstorage.com/public/index.json - Human page: https://data.bunnytech.app/datasets/monitorul-oficial The manifest is the contract: file URLs, row counts, column types, min/max statistics and example queries all live there. Re-read it to discover a new version. ## Fastest path — Parquet exports Immutable, physically sorted snapshot exports. No catalog fetch, best row-group pruning, safe to cache forever. Register one view per table: ```sql INSTALL httpfs; LOAD httpfs; CREATE OR REPLACE VIEW acts AS SELECT * FROM read_parquet([ 'https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00000.parquet', 'https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00001.parquet', 'https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00002.parquet', 'https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00003.parquet', 'https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00004.parquet' ]); CREATE OR REPLACE VIEW issues AS SELECT * FROM read_parquet('https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/issues.parquet'); CREATE OR REPLACE VIEW issuers AS SELECT * FROM read_parquet('https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/issuers.parquet'); ``` Example queries: -- Every emergency ordinance published in 2024: The date filter is a bare range on mo_date, the leading sort column, so parquet row-group statistics skip every other year. Written as year(mo_date) = 2024 it would read the whole table instead. ```sql ATTACH IF NOT EXISTS 'ducklake:https://data-directory.fsn1.your-objectstorage.com/catalog/catalog.ducklake' AS "datadirectory" (READ_ONLY); SELECT mo_date, mo_number, act_number, title, source_url FROM datadirectory.monitorul_oficial.acts WHERE mo_date >= DATE '2024-01-01' AND mo_date < DATE '2025-01-01' AND act_type = 'ORDONANȚĂ DE URGENȚĂ' ORDER BY mo_date DESC, mo_number DESC ``` -- What the Constitutional Court decided last year: Match on issuer_lc, the accent-folded companion column. It folds the repaired issuer, recovered from the act title, so both spellings the source uses — "CURTEA CONSTITUŢIONALĂ" (cedilla) and "Curtea Constituțională" (comma-below) — reduce to the same "curtea constitutionala". Folding the API's own Emitent field instead would give "curtea constitu?ionala" and this query would never match; that is what issuer_raw preserves and issuer repairs. ```sql ATTACH IF NOT EXISTS 'ducklake:https://data-directory.fsn1.your-objectstorage.com/catalog/catalog.ducklake' AS "datadirectory" (READ_ONLY); SELECT mo_date, act_type, act_number, title FROM datadirectory.monitorul_oficial.acts WHERE mo_date >= DATE '2025-01-01' AND mo_date < DATE '2026-01-01' AND issuer_lc LIKE '%curtea constitutionala%' ORDER BY mo_date DESC LIMIT 200 ``` ## Live lake — DuckLake catalog with time travel Attach the published catalog read-only over plain https. This works in native DuckDB AND in duckdb-wasm in the browser — the reader catalog resolves its data files through public https URLs, so no credentials and no backend are involved. ```sql INSTALL ducklake; LOAD ducklake; ATTACH 'ducklake:https://data-directory.fsn1.your-objectstorage.com/catalog/monitorul-oficial/catalog.ducklake' AS monitorul_oficial (READ_ONLY); SELECT * FROM monitorul_oficial.main.acts LIMIT 5; USE monitorul_oficial; ``` - Latest catalog: https://data-directory.fsn1.your-objectstorage.com/catalog/monitorul-oficial/catalog.ducklake - This exact version: https://data-directory.fsn1.your-objectstorage.com/catalog/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/catalog.ducklake (sha256 c20bbd6cbf766a7fa275401235b87c59ea0ccf7ea0a81ae85c2266f39b6f01cd) - Written by DuckDB v1.5.5 - Time travel: this ingest is snapshot 16 — e.g. `SELECT * FROM monitorul_oficial.acts AT (VERSION => 16)` ## Wholesale — S3 access For bulk downloads, read the bucket prefix directly over S3 with httpfs: ```sql INSTALL httpfs; LOAD httpfs; CREATE SECRET hetzner ( TYPE s3, ENDPOINT 'fsn1.your-objectstorage.com', URL_STYLE 'path', KEY_ID '', SECRET '' ); SELECT * FROM read_parquet('s3://data-directory/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/**/*.parquet'); ``` ## Schema ### acts One row per act published in Monitorul Oficial al României — or, for the pre-1989 period, in Buletinul Oficial — sourced from the Portal Legislativ of the Ministry of Justice. A row carries the act's complete text and metadata as most recently published; it is updated in place as the portal appends amendments and issues consolidated versions. - 208.1K rows · 507 MB · write mode `upsert` - Physically sorted by: `mo_date`, `mo_number`, `document_id` - Primary key: `document_id` - Text search columns: `title`, `issuer` - Files: 5 - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00000.parquet (41.5K rows) - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00001.parquet (41.2K rows) - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00002.parquet (41.6K rows) - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00003.parquet (41.5K rows) - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/acts/part-00004.parquet (42.4K rows) Columns: - `document_id` BIGINT NOT NULL — The Portal Legislativ document id, parsed from the record's LinkHtml. Stable across revisions and republications; the primary key. (range: "1" … "99998") (~202230 distinct) - `act_type` VARCHAR — The act type verbatim as published by the source, in Romanian: LEGE, HOTĂRÂRE, ORDONANȚĂ, ORDONANȚĂ DE URGENȚĂ, DECRET, ORDIN, DECIZIE, and roughly 166 others. Not normalised — filter on the exact source string. - `act_number` VARCHAR — The act's own number within its type and year, e.g. "301" or "1.348". VARCHAR rather than an integer because the source emits values with thousands separators and suffixed forms that a numeric column would reject or mangle. - `issuer` VARCHAR — The issuing authority, recovered from the EMITENT segment of the act's own title. The source's Emitent field cannot be used: the API replaces every ș and every ț in it with a literal '?' (it returns 'Curtea Constitu?ională', 'Camera Deputa?ilor'), and the title carries the same authority undamaged. The value is therefore the authority as the title prints it — usually uppercase, and usually spelled with the cedilla diacritics ş/ţ rather than ș/ț ('CURTEA CONSTITUŢIONALĂ'). For the few acts whose title has no EMITENT segment this falls back to the Emitent field, but only when that field arrived undamaged. NULL therefore means the authority is UNRECOVERABLE, not that the act has none: the title named no issuer and the API field was corrupted, so the only spelling on offer had a ? where a letter belongs. issuer_raw always holds what the API actually sent, so the evidence is never lost. The title's casing is not consistent across eras — older records shout 'GUVERNUL', newer ones write 'Guvernul' — so group and join on issuer_lc, which folds both to one value. - `issuer_lc` VARCHAR — issuer — the value recovered from the title, never the corrupted Emitent field — accent-folded and lowercased, for case- and accent-insensitive search. Folding the raw field would leave the API's '?' sitting where the letter belongs ('curtea constitu?ionala'), which no sensible pattern can match; folding the recovered value gives 'curtea constitutionala'. NULL means the same thing it means on issuer: the authority was unrecoverable — no EMITENT segment in the title and a corrupted API field — not that the act has no issuer. Those acts are the ones with no row in the issuers dimension. Filter on issuer_lc, never lower(issuer) — a function on a column cannot use parquet statistics. - `issuer_raw` VARCHAR — The Emitent field exactly as the API returned it, unrepaired — including the corruption that makes it unusable: the API replaces every ș and every ț with a literal '?', so values arrive as 'Curtea Constitu?ională' or 'Ministerul Finan?elor Publice'. Over a 70-record sample, 16 records and 8 of the 12 distinct authorities were affected; ă, â and î survive, only ș and ț are destroyed, and irreversibly so. issuer holds the repaired value, read out of the act title. This column exists so that nothing the source actually said is hidden — use it to audit the repair or to match the upstream API verbatim, never to group, join or search. - `title` VARCHAR — The act's full title as published. - `title_lc` VARCHAR — title, accent-folded and lowercased, for case- and accent-insensitive search. Filter on title_lc, never lower(title) — a function on a column cannot use parquet statistics. - `publication` VARCHAR — Which official publication carried the act: 'Monitorul Oficial' for the current gazette, or 'Buletinul Oficial' for the pre-1989 predecessor. - `mo_part` VARCHAR — The Part the act appeared in ('Partea I', 'Partea a V-a'), only when the source states it explicitly. Usually null: Partea I is the implicit default in the source and is not repeated on every record, so a null here must NOT be read as 'part unknown' — it almost always means Partea I. - `mo_number` INTEGER — The gazette issue number the act appeared in. (range: 0 … 9562) - `mo_is_bis` BOOLEAN — True when the citation names a 'bis' companion issue — the extra issue the gazette prints under the same number and date when one day's material does not fit in one. Read it as 'this act is in the bis issue', and note that a citation like 'nr. 611 şi 611 bis din 18 august 2014' means the act SPANS BOTH issues rather than replacing the regular one with the bis. mo_number is the shared number either way, so it stays joinable. - `mo_date` DATE — The gazette publication date — the Europe/Bucharest calendar day printed on the issue, with no time-of-day component. (range: "1837-12-07" … "2026-10-16") - `effective_date` DATE — DataVigoare from the source: the date the act enters into force, the Europe/Bucharest calendar day with no time-of-day component. Often but not always equal to mo_date — an act can be published ahead of, or take effect some time after, its publication date. - `full_text` VARCHAR — The complete plain text of the act as published, including any amendment footnotes the portal has appended since first publication. Can be very large — one sampled act ran to roughly 357,000 characters. - `text_length` INTEGER [UTF-16 code units] — Length of full_text in UTF-16 code units, so a query can size or filter results without reading the text column itself. Not the same as DuckDB's length(full_text), which counts code points: the two differ for characters above U+FFFF. Romanian text has none, so in practice they agree, but do not assume it for text quoted from other alphabets. - `source_url` VARCHAR — The Portal Legislativ permalink for this act: https://legislatie.just.ro/Public/DetaliiDocument/. ### issues One row per gazette issue actually seen: a Monitorul Oficial or Buletinul Oficial number, on a given date, in its regular or its bis printing. A pure roll-up of (publication, number, bis, date) over acts — identity and nothing else, no counts. It answers "which issues exist in this dataset" and gives a join target for the same four columns on acts; "how many acts are in an issue" is one GROUP BY over acts and is exact at the moment it is asked, which a stored count computed by whichever ingest ran last could not be. The Part is not here: the source names one for almost no act, so an issue row could only ever guess it from whichever of its acts sorted first — see acts.mo_part. - 35.1K rows · 52 KB · write mode `upsert` - Physically sorted by: `mo_date`, `mo_number`, `mo_is_bis` - Primary key: `publication`, `mo_number`, `mo_is_bis`, `mo_date` - Files: 1 - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/issues.parquet (35.1K rows) Columns: - `publication` VARCHAR NOT NULL — Which publication this issue belongs to: 'Monitorul Oficial' or 'Buletinul Oficial'. (~2 distinct) - `mo_number` INTEGER NOT NULL — The gazette issue number. (range: 0 … 9562) (~1669 distinct) - `mo_is_bis` BOOLEAN NOT NULL — Whether this is the 'bis' printing of the number rather than the regular one. The gazette issues a bis companion under the same number and date when a day's material does not fit in one issue, so nr. 611 and nr. 611 bis of 18 August 2014 are two distinct issues that share a number — which is exactly why this column is part of the key. An act cited as appearing in 'nr. 611 şi 611 bis' spans both, and is counted in both rows. (range: "false" … "true") (~2 distinct) - `mo_date` DATE NOT NULL — The publication date of this issue — the Europe/Bucharest calendar day, with no time-of-day component. (range: "1837-12-07" … "2026-10-16") (~10957 distinct) ### issuers One row per issuing authority, so a reader can look up who has issued acts without scanning the fact table's issuer text on every query. Identity and a display name only: "how many acts did this authority issue" is a GROUP BY over acts, exact whenever it is asked, where a stored count would only ever describe whichever ingest wrote the row last. - 1,175 rows · 31 KB · write mode `upsert` - Physically sorted by: `issuer_lc` - Primary key: `issuer_lc` - Files: 1 - https://data-directory.fsn1.your-objectstorage.com/public/monitorul-oficial/v/01M5423ZBM0YYV1R4HMX4TERH0/issuers.parquet (1,175 rows) Columns: - `issuer_lc` VARCHAR NOT NULL — The issuing authority's name, accent-folded and lowercased, and this dimension's stable identity. The source spells and cases the same authority differently across eras — both casing (older records shout 'GUVERNUL', newer ones write 'Guvernul') and diacritic style (cedilla 'CURTEA CONSTITUŢIONALĂ' versus comma-below 'Curtea Constituțională') — so issuer_lc is the one value every spelling of an authority folds to, no matter which era or which diacritic convention the source used that day. One row per issuer_lc: group and join on this column, never on issuer. (range: "; guvernul romaniei" … "uniunea pentru protectia noilor soiuri de plante") (~1295 distinct) - `issuer` VARCHAR — One representative spelling of this authority's name, recovered from an act's title the same way acts.issuer is (see that column). Because the source's spelling and casing for one authority is inconsistent across eras, this is a display label only, chosen deterministically as the lexicographically smallest (by code point) of the distinct spellings seen for this issuer_lc — not necessarily the most common or most recent one. issuer_lc is the stable identity to join and group on. ## Performance notes - There are no indexes in a lakehouse. The physical sort order plus Parquet row-group min/max statistics ARE the index. Predicates on the leading sort columns prune whole row groups; everything else is a full column scan. - `acts` prunes on `mo_date` → `mo_number` → `document_id`. - `issues` prunes on `mo_date` → `mo_number` → `mo_is_bis`. - `issuers` prunes on `issuer_lc`. - `ILIKE '%needle%'` cannot prune: it decompresses that whole column. Prefer prefix predicates on the lowercased search companion columns where they exist. - Every file URL under `/v//` is immutable. Cache it as aggressively as you like. - Files are never rewritten in place — a new ingest writes a new version path. Re-read the manifest to pick up updates rather than polling the file URLs. - Pull only the columns you need. Parquet is columnar and the reader range-GETs what it reads. ## Do not - Do not scrape https://data.bunnytech.app HTML. Every number on those pages comes from the manifest above. - Do not hit the upstream source (https://legislatie.just.ro/) in bulk. This mirror exists so you do not have to. - Do not read DuckLake internal data files with a plain Parquet reader. They come with positional delete files, and ignoring those silently returns deleted rows. Use the ducklake extension, or use the published exports above. - Do not republish without the attribution line, and do not imply endorsement.