EUR-Lex URLs and the EUR-Lex web service, explained for developers.
A EUR-Lex document is addressed by its CELEX number: legal-content/EN/TXT/?uri=CELEX:32016R0679 is the GDPR in English. Everything else in the link — TXT or ALL, HTML or PDF, a qid — either picks a view of that document or is not needed at all.
Below: what each part of a document link and a search link means, how CELEX numbers and ELIs are built, and the official machine routes — the EUR-Lex web service and the Publications Office’s Cellar — with what each is good and bad at.
Anatomy of a legal-content URL.
https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32016R0679
https://eur-lex.europa.eu/legal-content/EN/ALL/?uri=CELEX:32016R0679
https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32016R0679
https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32016R0679
https://eur-lex.europa.eu/legal-content/EN/TXT/XML/?uri=CELEX:32016R0679| Part | What it means |
|---|---|
https://eur-lex.europa.eu/legal-content/ | The document pages of EUR-Lex. |
EN | The language of the page: any of the 24 official EU languages, as an upper-case two-letter code (EN, FR, DE, …). |
TXT/ | The document’s text page on EUR-Lex. |
ALL/ | The document’s information page: title, dates, author, classification and relations to other acts. |
TXT/HTML/ · TXT/PDF/ · TXT/XML/ | The text alone, as HTML, PDF or XML. |
?uri=CELEX:32016R0679 | The document itself, by its CELEX number. Browsers often percent-encode the colon (CELEX%3A32016R0679); it is the same address. |
&qid=… | Not part of the address. Links copied from EUR-Lex often carry it, for example on pages opened from a search; drop it and the URL still names the same document. |
EUR-Lex also links legislation by its ELI, for example https://eur-lex.europa.eu/eli/reg/2024/1689/oj for the AI Act (§ 03). To store a reference, store the CELEX number; you can rebuild every link above from it.
Sector, year, type, number.
3 2016 R 0679
│ │ │ └─ number, padded to four digits
│ │ └──── type: R regulation, L directive, D decision
│ └────────── year
└───────────── sector: 3 = legislation32016R0679 is Regulation (EU) 2016/679, the GDPR. In case law (sector 6) the year is the year the case was brought and the letters name the court and the kind of document: 62018CJ0311 is the Court of Justice judgment in case C-311/18, and an Advocate General’s opinion in the same case would read 62018CC0311.
| Main sectors | What | Example |
|---|---|---|
0 | Consolidated versions | 02016R0679-20160504 |
1 | Treaties | — |
2 | International agreements | — |
3 | Legislation | 32016R0679 (GDPR), 32024R1689 (AI Act) |
4 | Complementary legislation | — |
5 | Preparatory acts | — |
6 | Case law | 62018CJ0311 (Schrems II, C-311/18) |
9 | Parliamentary questions | — |
| Letters | Type | In |
|---|---|---|
R | Regulation | sector 3 |
L | Directive | sector 3 |
D | Decision | sector 3 |
CJ | Court of Justice judgment | sector 6 |
CC | Advocate General’s opinion | sector 6 |
CO | Court of Justice order | sector 6 |
TJ · TO | General Court judgment · order | sector 6 |
Suffixes
- Consolidated versions — sector 0, the base act’s number and the consolidation date:
02016R0679-20160504. They are the Publications Office’s documentation tool; the authentic text is the one published in the Official Journal. - Corrigenda — the act’s number with
R(01),R(02)…:32008R1272R(01). - Sequence qualifiers — a number in brackets, as in
32019D0003(01). Brackets must be percent-encoded (%28,%29) when the number goes into a Cellar URL.
The European Legislation Identifier.
http://data.europa.eu/eli/reg/2024/1689/oj → 32024R1689 (regulation: R)
http://data.europa.eu/eli/reg/2016/679/oj → 32016R0679
eli/dir/{year}/{number} → 3{year}L{number, 4 digits} (directive: L)
eli/dec/{year}/{number} → 3{year}D{number, 4 digits} (decision: D)For regulations, directives and decisions the mapping is usually mechanical: sector 3, the year, the type letter and the number padded to four digits. Note the letter for a directive is L, not D. It is not always so: some acts carry a CELEX with a sequence qualifier that the ELI doesn’t show — eli/dec/2019/166/oj is CELEX 32019D0003(01), not 32019D0166. When it matters, and for other ELI types, look it up — Cellar SPARQL returns a document’s ELI as cdm:resource_legal_eli (§ 05).
The parameters of a search URL.
https://eur-lex.europa.eu/search.html?type=advanced&lang=en
&DTS_DOM=EU_LAW&SUBDOM_INIT=EU_LAW&DTS_SUBDOM=LEGISLATION
&textScope0=ti-te&andText0=artificial+intelligence
&DD_YEAR=2024&FM_CODED=REG| Parameter | What it does |
|---|---|
type=advanced | The advanced search form. |
lang | Interface language, lower case (en). |
DTS_DOM | The collection: EU_LAW for EU law, ALL for every collection. |
SUBDOM_INIT | Sent with DTS_DOM, set to the same collection (ALL_ALL when searching everything). |
DTS_SUBDOM | A part of the collection: LEGISLATION, CONSLEG (consolidated texts), TREATIES, EU_CASE_LAW, PRE_ACTS (preparatory acts), INTER_AGREE, PAR_QUESTION, LEGAL_PROCEDURE, or ALL_ALL. |
textScope0 + andText0 | Search text (andText0) and where to look for it (textScope0): ti = title, te = text, ti-te = both. |
DD_YEAR · DD_MONTH · DD_DAY | Date of the document; the …_TO variants (DD_YEAR_TO, DD_MONTH_TO, DD_DAY_TO) close a range. |
FM_CODED | Document form: REG, DIR, DEC, JUDG, ORDER, OPIN, COMMUNIC, REG_IMPL, DEC_IMPL, … |
AU_CODED | Author: COM (Commission), CONSIL (Council), EP (Parliament), CJ (Court of Justice), … |
PROC_TYP | Procedure type, for example OLP (ordinary legislative procedure). |
What we learned the hard way
- Only the first
FM_CODEDcounts:FM_CODED=REG&FM_CODED=DIRreturns regulations only. Run one search per form. - Only the first
DTS_SUBDOMcounts too. - A form filter with a full-year day range (1 January to 31 December, as
DD_DAY/DD_MONTH) returns nothing; withDD_YEARalone it works. AU_CODEDhas a working value for the Court of Justice (CJ) but none for the General Court: filter its documents by CELEX instead (sector 6, letterT).
The web service, Cellar, and the website.
| Route | Gives you | Access | Watch out for |
|---|---|---|---|
| EUR-Lex web service (SOAP) | Search: an expert query in, matching documents’ metadata out (title, date, form, author, languages, links), up to 100 per page. Full-text search included (TE ~). | Register with an EU Login account; registration is reviewed before access is granted. A daily call quota per account. | SOAP 1.2 with a WS-Security password token. Calls made back to back fault or return zero hits: space them out. Returns no parsed text. |
| Cellar SPARQL | Metadata and relations for any document: dates, ELI, ECLI, type, author, Official Journal reference, amendments, consolidated versions. | Open: no registration, no key. | No full-text search of document content. No service level: long queries are cut off at about 60 seconds. |
| Cellar content negotiation (REST) | The document itself: XHTML text, Formex XML, PDF, or the metadata notice, by CELEX number. | Open: no registration, no key. | Accept and a three-letter Accept-Language are required. You parse the XHTML or Formex yourself. Some older acts exist only as PDF scans. |
| eur-lex.europa.eu pages | The pages people read: text, information page, search results. | Open in a browser. | Behind a web application firewall: plain HTTP clients get a JavaScript challenge (HTTP 202), not the page. Not an interface for programs. |
The EUR-Lex web service (search)
A SOAP 1.2 service at https://eur-lex.europa.eu/EURLexWebService, authenticated with a WS-Security username token. The username is your EU Login id, not your email address. A request carries an expert query, a page number, a page size (at most 100) and a search language:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:sear="http://eur-lex.europa.eu/search">
<soap:Header>
<wsse:Security soap:mustUnderstand="true"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>your-eu-login-id</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">…</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<sear:searchRequest>
<sear:expertQuery>TI ~ "artificial intelligence" AND FM_CODED = REG AND DD >= 01/01/2024</sear:expertQuery>
<sear:page>1</sear:page>
<sear:pageSize>100</sear:pageSize>
<sear:searchLanguage>en</sear:searchLanguage>
</sear:searchRequest>
</soap:Body>
</soap:Envelope>| Expert-query field | Meaning |
|---|---|
TI ~ "…" · TE ~ "…" | Words in the title · in the text |
DD >= 01/01/2024 | Date of the document, as dd/mm/yyyy (with <= for the end of a range) |
FM_CODED = REG | Document form — the same codes as the search URL |
AU_CODED = COM | Author |
DTS_SUBDOM = LEGISLATION | Part of the collection |
- Clauses combine with
AND/ORand brackets, and several values of one field are anOR:(FM_CODED = REG OR FM_CODED = DIR)— one call, unlike the search URL. DTS_DOMis a URL parameter, not an expert-query field:DTS_DOM = EU_LAWmatches nothing. EU law is the default collection, so leave it out.- For a date of document use
DD.DTAis a different field:DTA = 2026with judgments returned 2 hits where theDDrange for 2026 returned 599. - Space your calls out (we wait a second between calls): back-to-back calls fault with “The call must not be performed within the idle interval” — or answer with zero hits.
Cellar SPARQL (metadata)
Cellar is the Publications Office repository that feeds EUR-Lex. Its SPARQL endpoint, https://publications.europa.eu/webapi/rdf/sparql, answers anonymous POST requests; reuse, commercial included, is allowed under Decision 2011/833/EU with the source acknowledged. This query returns the AI Act’s date, Official Journal publication date and ELI:
curl https://publications.europa.eu/webapi/rdf/sparql \
-H 'Accept: application/sparql-results+json' \
--data-urlencode [email protected]
# q.rq
PREFIX cdm: <http://publications.europa.eu/ontology/cdm#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?dateOfDocument ?ojPublished ?eli WHERE {
?work cdm:resource_legal_id_celex "32024R1689"^^xsd:string ;
cdm:work_date_document ?dateOfDocument ;
cdm:official-journal-act_date_publication ?ojPublished ;
cdm:resource_legal_eli ?eli .
}
# → 2024-06-13, 2024-07-12, http://data.europa.eu/eli/reg/2024/1689/oj- Type the CELEX literal:
"32024R1689"^^xsd:string. Untyped, the same query returns zero rows, without an error. cdm:work_date_document(the act’s date) andcdm:official-journal-act_date_publication(its Official Journal date) are different dates — pick the one you mean.- Grouping across documents? Aggregate typed dates as
MAX(STR(?date)): an aggregate over the typed value can return another group’s date. - Titles are searchable (
bif:contains); document text is not — that is what the web service is for.
Cellar content negotiation (the document itself)
Every document has a URL by CELEX number under http://publications.europa.eu/resource/celex/; the format is chosen with the Accept header and the language with a three-letter Accept-Language (eng, deu, fra…):
# XHTML text (the markup EUR-Lex shows, article ids included)
curl -L -H 'Accept: application/xhtml+xml' -H 'Accept-Language: eng' \
http://publications.europa.eu/resource/celex/32024R1689
# Formex 4 XML, as a zip
curl -L -H 'Accept: application/zip;mtype=fmx4' -H 'Accept-Language: eng' \
http://publications.europa.eu/resource/celex/32016R0679 -o gdpr-fmx4.zip
# The metadata notice
curl -L -H 'Accept: application/xml;notice=branch' -H 'Accept-Language: eng' \
http://publications.europa.eu/resource/celex/32016R0679- Without
Accept-Languagethe request fails with 400.text/htmlis not a format Cellar serves documents in: ask forapplication/xhtml+xml. - Formex as
application/xml;mtype=fmx4fails; the zip always works. - Percent-encode brackets in a CELEX number (
32013R0952R%2804%29); unencoded, the request 404s. - Not every document has every format. Many regulations from before 2005 exist only as scanned PDFs; in our checks EUR-Lex had no HTML text for them either.
Skip the parsing: LexAPI.
LexAPI takes any of the identifiers above and returns the document as JSON — metadata, full text, and the articles, recitals and annexes as separate items. One API key in the x-api-key header; requests copied from the documentation.
# A pasted EUR-Lex link — qid and all; the CELEX is read from uri=
curl -X POST "https://lex-api.com/api/v1/documents/url" \
-H "x-api-key: $LEX_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32016R0679"}'
# Any identifier — CELEX, EUR-Lex URL, ELI or ECLI — to the CELEX and its four EUR-Lex URLs
curl -X POST "https://lex-api.com/api/v1/resolve" \
-H "x-api-key: $LEX_KEY" \
-H "Content-Type: application/json" \
-d '{"identifier":"http://data.europa.eu/eli/reg/2024/1689/oj"}'
# The document by CELEX — or one article of it
curl -X POST "https://lex-api.com/api/v1/documentContent" \
-H "x-api-key: $LEX_KEY" \
-H "Content-Type: application/json" \
-d '{"celexNumber":"32024R1689","articleId":"art_50","include":["metadata","articles"]}'Costs: a document read is 5 credits, settled at 1 when it is served from the LexAPI corpus and 4 when it comes from Cellar; /resolve is 1. /documents/url reads the English text; /documentContent takes a language. The Free plan starts with 500 credits, then 150 a month, no card. Searching works the same way — POST /api/v1/search takes plain parameters (query, documentType, dateFrom…) instead of an expert query. By-URL reference →
N° 01What does qid mean in a EUR-Lex URL?+
N° 02What is the difference between TXT, ALL, HTML and PDF in a EUR-Lex link?+
N° 03How is a CELEX number structured?+
N° 04Is there an official EUR-Lex search API or web service?+
N° 05What is the Cellar RESTful API?+
N° 06How do I get a EUR-Lex document as JSON?+
Sources: LexAPI’s own EUR-Lex and Cellar clients, and live checks against the Cellar SPARQL endpoint and content negotiation (November 2026). The EUR-Lex web service and Cellar are run by the Publications Office of the European Union; LexAPI is not affiliated with it.