zefix-parser
Typed Python client for Zefix, the Swiss Central Business Name Index (Zentraler Firmenindex).
Covers both ways into the register: the open LINDAS SPARQL dataset, which carries every company in Switzerland and needs no credentials, and the Zefix PublicREST API, which adds share capital, legal status, auditors and corporate relations. Responses parse into plain dataclasses.
Built and maintained by Prospex, a Swiss B2B sales intelligence platform.
Install
pip install zefix-parser
To use the HTTP clients (for fetching from the live endpoints):
pip install zefix-parser[http]
Quick start
Read the register from LINDAS
No credentials needed.
from zefix_parser.client import LindasClient
with LindasClient() as client:
print(client.count()) # 812,000 or so
for entity in client.iter_entities():
print(entity.legal_name, entity.uid, entity.canton, entity.legal_form_code)
Or look up companies you already have UIDs for, in one request:
from zefix_parser.client import LindasClient
with LindasClient() as client:
entities = client.fetch_by_uids(["CHE-105.215.703", "CHE-411.462.297"])
for entity in entities:
print(entity.legal_name) # "Alpenblick Handel AG"
print(entity.purpose) # "Handel mit Waren aller Art"
print(entity.municipality_name, entity.canton)
Fetch details from the PublicREST API
The REST API is gated behind HTTP Basic auth. Credentials are issued on request by
zefix@bj.admin.ch.
from zefix_parser.client import ZefixRestClient
with ZefixRestClient(username="...", password="...") as client:
company = client.get_by_uid("CHE-105.215.703")
print(company.name) # "Alpenblick Handel AG"
print(company.capital_nominal) # Decimal("250000.00")
print(company.status) # "ACTIVE"
for auditor in company.audit_companies:
print(auditor.name, auditor.legal_seat)
Both clients rate-limit themselves to one request every half second and retry transient failures with exponential backoff.
Parse responses you already have
Every parser is importable without the http extra, so you can point them at recorded
responses or use your own HTTP library:
from zefix_parser import parse_company, parse_entity_page
company = parse_company(rest_json) # a dict from the REST API
entities = parse_entity_page(sparql_bytes) # a SPARQL JSON results document
The two access paths
| LINDAS | PublicREST | |
|---|---|---|
| Endpoint | https://ld.admin.ch/query |
https://www.zefix.admin.ch/ZefixPublicREST/api/v1 |
| Credentials | none | HTTP Basic |
| Shape | the whole register, keyset-paginated | one company per request |
| Carries | name, legal form, address, canton, purpose | the above plus capital, status, auditors, branches, mergers, former names |
| Class | RegistryEntity |
Company |
LINDAS has no modification-date predicate, so a server-side delta fetch is impossible: you either walk the whole register or drive updates from another change feed, such as SHAB publications.
Data model
parse_entity_page() returns RegistryEntity objects:
@dataclass(frozen=True)
class RegistryEntity:
zefix_uri: str
uid: str # CHE123456789, unpunctuated
chid: str
ehra_id: str
legal_name: str
alternate_names: list[str] # the other language variants
legal_form_code: str # eCH-0097, e.g. "0106"
legal_form_name: str
municipality_id: str # federal municipality number
municipality_name: str
canton: str
street_address: str
postal_code: str
locality: str
purpose: str
purpose_language: str
fingerprint: str # SHA-256 over the identity fields
parse_company() returns Company objects:
@dataclass(frozen=True)
class Company:
name: str
ehraid: int
uid: str
chid: str
canton: str
status: str # "ACTIVE", "IN_LIQUIDATION", "DELETED"
capital_nominal: Decimal | None
capital_currency: str
deletion_date: date | None
cantonal_excerpt_web: str
head_offices: list[RelatedEntity]
further_head_offices: list[RelatedEntity]
branch_offices: list[RelatedEntity]
has_taken_over: list[RelatedEntity]
was_taken_over_by: list[RelatedEntity]
audit_companies: list[RelatedEntity]
old_names: list[OldName]
Identifiers
The same UID appears in three forms depending on where you read it, so the library converts between them:
from zefix_parser import clean_uid, format_uid, is_valid_uid, normalize_uid
normalize_uid("CHE-105.215.703") # "CHE105215703" (LINDAS form)
format_uid("CHE105215703") # "CHE-105.215.703" (REST form)
clean_uid("VAT: CHE-109.807.630 MWST") # "CHE109807630"
is_valid_uid("CHE123456789") # False - the check digit fails
is_valid_uid() runs the ISO 7064 mod 11-10 check digit. It is worth calling before you
spend a request: a mistyped UID can never match the register, and the register's own
placeholder CHE123456789 fails it.
Legal forms
Both registers identify a legal form by its four-digit eCH-0097 code, and the name differs by language:
from zefix_parser import LegalForm, legal_form_abbreviation, legal_form_name
LegalForm.CORPORATION # "0106"
legal_form_name("0106", "de") # "Aktiengesellschaft"
legal_form_name("0106", "fr") # "Société anonyme"
legal_form_name("0106", "it") # "Società anonima"
legal_form_abbreviation("0107", "fr") # "Sàrl"
The full table is in the legal forms reference.
Former names
The register re-typesets a company's name whenever anything else about it changes, so
company.old_names fills up with entries that differ from the current name only in casing
or spacing: "QualiCasa AG" against "Qualicasa AG". Apply them and you retire the company's
live name. meaningful_old_names() drops them:
from zefix_parser import meaningful_old_names
for old in meaningful_old_names(company):
print(old.sequence_nr, old.name) # only the genuine renames, oldest first
API reference
zefix_parser.parse_entity_page(content: bytes) -> list[RegistryEntity]
Parse a SPARQL JSON results document into companies. One company spans several rows, one per language-tagged literal; rows are grouped by entity URI and folded down to a single deterministic value per field.
zefix_parser.parse_company(data: dict | list) -> Company
Parse one /company/... response. The API is inconsistent about whether a single company
comes back as an object or a one-element list; both work.
zefix_parser.build_combined_page_query(*, cursor_after=None, limit=500) -> str
Build the SPARQL query for one keyset page of full records. Use this to run the crawl
yourself, outside LindasClient.
zefix_parser.client.LindasClient
SPARQL client. count(), iter_entities(), iter_pages() (which yields RawPage objects
carrying the cursor, so a crawl can be resumed), fetch_by_uids(), query().
zefix_parser.client.ZefixRestClient
PublicREST client. get_by_uid(), get_by_ehraid(), get_by_chid(), search(),
sogc_by_date(), sogc().
Background
Zefix (the Zentraler Firmenindex, index central des raisons de commerce, indice centrale
delle ditte, officially the Swiss Central Business Name Index) is the federal index over
the 26 cantonal commercial registers: Handelsregister, registre du commerce, registro di
commercio. Every company registered in Switzerland appears in it, identified by a UID
(CHE-123.456.789), a CHID and an EHRAID.
The Federal Office of Justice publishes the index twice. LINDAS carries every company as linked data, open to anyone, holding each company's current state. The PublicREST API holds more per company, behind credentials, and answers one lookup at a time. Neither publishes a change feed; for that you need the gazette, which is what shab-parser reads.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zefix_parser-0.1.0.tar.gz.
File metadata
- Download URL: zefix_parser-0.1.0.tar.gz
- Upload date:
- Size: 18.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88aeb3e3e4ad6f0125733f9291075241272e385773f94101b7fafbf0b00e937e
|
|
| MD5 |
0f62d446ea80b0068dd29511bec8caf8
|
|
| BLAKE2b-256 |
f0c9bae67b781a2d19b30648f3c0b1f8f1e167f889c8bc3fe28d8f5058a99635
|
File details
Details for the file zefix_parser-0.1.0-py3-none-any.whl.
File metadata
- Download URL: zefix_parser-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68cde3f634edcb119a787b7dd567652199b52ba54254580de235a79404c31c1f
|
|
| MD5 |
ce7b438858e4640e7341a9ddd73705e6
|
|
| BLAKE2b-256 |
02b5a1f1f028cfa09fc018c77f27514047df939c45b7cf7a43280f1c4d4b35a6
|