euipo-tm-client
Minimal Python client for the EUIPO (European Union Intellectual Property Office) trademark search API.
It is a thin, synchronous wrapper (built on httpx)
that handles OAuth2 authentication and returns responses as raw parsed JSON
(dict). It covers the two core endpoints: searching for trade marks and
retrieving the details of a single trade mark.
Installation
pip install euipo-tm-client
Configuration
The client reads credentials from environment variables (you can keep them in a
.env file in the working directory — real environment variables take
precedence):
| Variable | Description |
|---|---|
EUIPO_API_KEY |
Your application's client ID |
EUIPO_API_SECRET |
Your application's client secret |
EUIPO_ENVIRONMENT |
"sandbox" (default) or "production" |
Obtain credentials and subscribe your application to the Trademark search API plan via the EUIPO developer portal.
Usage
from euipo_tm_client import TrademarkSearchClient
with TrademarkSearchClient() as client:
# Search using an RSQL query expression.
results = client.search_trademarks(
query="wordMarkSpecification.verbalElement==apple",
size=10,
)
print(results["totalElements"])
for tm in results["trademarks"]:
print(tm["applicationNumber"], tm.get("status"))
# Retrieve full details for one trade mark.
detail = client.get_trademark("018692868", language="en")
print(detail["status"])
Credentials and environment can also be passed explicitly instead of via the environment:
client = TrademarkSearchClient(
api_key="...", api_secret="...", environment="production",
)
Errors
API and authentication failures raise typed exceptions, all subclasses of
EUIPOError:
EUIPOAuthError— token acquisition failed.EUIPOAPIError— the API returned a non-2xx response; exposes.status_codeand the parsed.body.
Query language (RSQL)
The query argument of search_trademarks() accepts an RSQL (REST Query
Language) expression — a compact, URL-friendly filter syntax. A clause is
field + operator + value, and clauses combine with and / or (use
parentheses to group). RSQL avoids unsafe characters, so no URL encoding is
needed.
Comparison operators:
| Operator | Meaning |
|---|---|
== |
equal to (supports * as a wildcard) |
!= |
not equal to (supports * as a wildcard) |
< <= > >= |
range comparison (dates and numbers) |
=in= |
in a set, e.g. =in=(WORD,FIGURATIVE) |
=out= |
not in a set |
=all= |
contains all of a set |
Each field supports only a subset of these operators. Date fields
(applicationDate, registrationDate, expiryDate, …) expect yyyy-MM-dd
values. Examples:
# Verbal element exactly "apple"
wordMarkSpecification.verbalElement==apple
# Wildcard match + status, with nice-class membership
niceClasses=all=(25,28,40) and wordMarkSpecification.verbalElement==*Dog* and status==REGISTERED
# Date range with grouped OR logic
applicationDate>=2023-05-04 and ((markFeature==FIGURATIVE and niceClasses=all=(25,26)) or (markFeature==WORD and niceClasses=out=(40)))
The full grammar, the list of supported fields, and the operators each field
allows are documented in the query parameter of the OpenAPI spec
(specs/openapi.json).
Development
This project is managed with uv.
uv sync # install dependencies
uv run pytest # run the test suite (mocks HTTP; no live credentials needed)
uv run main.py # run the live sandbox demo (requires credentials)
Releasing
Releases publish to PyPI automatically when a GitHub Release is published — see RELEASING.md.
License
Release files for euipo-tm-client 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| euipo_tm_client-0.1.1.tar.gz | 26.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| euipo_tm_client-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.7 kB
Release files / euipo_tm_client-0.1.1.tar.gz
| Download URL | euipo_tm_client-0.1.1.tar.gz |
|---|---|
| Size | 26.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dfcf45574c41c3a09320ee88080408488f82a6eae532afa501a88f3d9ac9ad7b
|
|
BLAKE2b-256 checksum How to use checksums |
75fb21a3804624a32f7fbefa4cbea131b284945fa757d370e9f1b98f885043e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.
Transparency logRelease files / euipo_tm_client-0.1.1-py3-none-any.whl
| Download URL | euipo_tm_client-0.1.1-py3-none-any.whl |
|---|---|
| Size | 10.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e14e16bdae6dea4b2193abc343fa166ef5a9246b0ed165d15d6d182a86426727
|
|
BLAKE2b-256 checksum How to use checksums |
9933ec96c1be95281b54c211cfb81612f6d173257c905dd8fd58b485170c171e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.
Transparency log