# Switzerland

Swiss companies come from the federal commercial register (Zefix), the
federal UID register, the Swiss Official Gazette of Commerce (SOGC) and the
cantonal register excerpts. All five sources are official and open. Four of
them need no account; the Zefix REST API needs credentials that the
operator enters once (see [Activating Zefix REST](#activating-zefix-rest)).

## Sources

| Source | Gives | Access | Default |
|---|---|---|---|
| `lindas_zefix` (Zefix on LINDAS) | legal name and its de/fr/it/en versions, UID, CH-ID, EHRA-ID, legal form, seat municipality (BFS number), registered address, purpose | SPARQL, no login; active entities only, updated daily | on |
| `uid_register` (UID register, BFS) | master data of every UID, also outside the commercial register (administrations, sole traders, associations, VAT-only entities): names, legal form, UID and register status, legal and postal addresses, register entry and deletion dates, VAT status and number, LEI | SOAP, no login; about 20 requests per minute | on |
| `zefix_rest` (Zefix Public REST API) | the full register record, deleted companies included: status and deletion date, nominal capital, former names, SOGC publications, head and branch offices, mergers, audit firms, link to the cantonal excerpt | HTTP basic credentials from the Federal Office of the Commercial Register | **off** until credentials are set |
| `sogc` (Swiss Official Gazette of Commerce) | the events timeline: incorporation, name, seat, address, purpose and capital changes, officer changes (who joined or left, with dates), mergers, liquidation, deletion; the company as its latest publication states it; daily change feed | Amtsblattportal public API, no login; robots.txt not applied (official API, see [Access](#access)) | on |
| `ch_cantonal_excerpt` (cantonal register excerpts) | officers and signatories: name, role, signing authority, since/until, residence, origin or nationality as published | public excerpt pages through the residential proxy tier; robots.txt not applied (official register, see [Access](#access)) | on |

Where sources disagree, the register (Zefix, UID register, cantonal
excerpts) ranks above the gazette; every value keeps its source, and
conflicts are shown (see [Company data sources](/docs/companies-sources.md)).

## Access

How Cormorant reaches the two sources that need special handling. Both are
shown on the source card in Mission Control (**Company data → Sources**,
row *Access*).

### SOGC: robots.txt not applied (official API)

amtsblattportal.ch serves `User-agent: *` / `Disallow: /` for the whole host,
its public API (`/api/v1/publications`) included, so every request was
refused as `blocked`. The API is documented for public use and the operator
decided to use it regardless. The source therefore has the robots policy
`official_api` ("robots.txt: not applied (official API)"):

- only this connector's requests skip robots.txt, on both transport paths
  (plain GETs through the Fetcher and requests with headers or a body);
- its rate bucket (`amtsblattportal`, 1 request/s, burst 2), the
  per-domain politeness, the SSRF checks and the storage of the exact
  response bodies still apply;
- every other fetch, including `/v1/fetch` of the same host, still obeys
  robots.txt (`RESPECT_ROBOTS`).

The policy is reserved for documented official APIs the operator has
decided to use; web pages never get it.

The API negotiates its representation: a browser's `Accept` header gets
XML (`application/xhtml+xml`), so the source asks for
`Accept: application/json`. A response of another type fails as `parse`
with what came back ("expected application/json, got …"), and a cached
copy of another type is never used.

### Cantonal excerpts: through the premium routes

The cantonal register portals (e.g. prestations.vd.ch, zh.chregister.ch)
answer HTTP 403 to datacenter addresses, robots.txt included. Excerpt pages
are therefore fetched only through the premium routes:

- the residential proxy first, in a sticky session per portal host
  (renewed every 25 requests or 10 minutes, requests on one exit at least
  1.5 s apart), with the headers of a Chrome navigation;
- when the proxy is refused (403, 429, a challenge), the request is retried
  once on a new exit, then the rendering tier answers; refusals from 3
  different exits within 5 minutes skip the proxy for that host only, for
  5 minutes, doubling while refusals continue (at most an hour);
- never Cormorant's own egress for excerpt pages.

The chregister.ch portals (ZH, BE, LU, ZG, BS, TI) show the excerpt in a
panel that the page loads after itself (a JSF request). The source does the
same: it requests the page (never from the cache), then loads the panel with
a POST in the same residential-proxy session, and reads the panel. Both
requests are metered. The portals are asked in German, whatever the canton's
language: the German panel is the one verified in production (the English
one comes back empty). The rendering tier cannot send that POST, so these cantons
need the residential proxy; without it the source answers `not_configured`.
VD and GE have their own portals and are asked in French.

The canton (which portal to ask) comes from what the register already knows
about the company (its seat canton from Zefix or the UID register), else from
the source option `cantons`. Only for a company the register does not know
yet is it looked up on LINDAS (one SPARQL query from our own egress). The
canary (ABB Ltd, canton of Zurich) carries its canton and checks the excerpt
route itself.

**robots.txt: not applied (official register).** Every `*.chregister.ch`
portal and lindas.admin.ch serve `User-agent: *` / `Disallow: /`. These are
the official public commercial registers, and the operator decided that this
source reads them regardless: it has the robots policy `official_register`
("robots.txt: not applied (official register)" on the source card). Only
this source's own requests (excerpt pages and the LINDAS canton lookup) skip
robots.txt; its rate bucket (0.2 requests/s), the per-domain politeness, the
SSRF checks, the stored exact bodies, the premium route and the billing
below are unchanged, and every other fetch of these hosts, `/v1/fetch`
included, still obeys robots.txt.

**Cost.** Premium-route usage of the source is company-data pipeline cost, not
a customer's fetch: its premium attempts are reserved against the internal project
`company-data` (`COMPANY_DATA_PROJECT`, created on first use under the
internal customer with a monthly budget of `COMPANY_DATA_MONTHLY_BUDGET_USD`,
20 USD; change it in Mission Control). Each excerpt fetch that reached
the premium routes is one `request_log` row on that project with kind `company`
(billing category `company`, `reason = source:ch_cantonal_excerpt`), its
premium bytes and cost, so it shows with the company traffic and on the Costs
page and never counts towards a customer's premium fetches. Your own company
requests are metered as before.

Errors: `not_configured` when the premium routes or the `company-data` project is not
available, `budget_exhausted` when that project's budget is used up,
`blocked` for a refused destination (SSRF checks). The message says how;
a refused page lists every attempt ("all_tiers_failed [proxy 403 http_403,
proxy_render 403 http_403]").
The same text is shown with failing canary checks and **Test connection** in
Mission Control, and logged by the worker.

## Identifiers

| Scheme | Example | Notes |
|---|---|---|
| `ch_uid` | `CHE-101.049.653` | Enterprise identification number; the check digit is verified. `CHE101049653`, `CHE-101.049.653 MWST` and `che 101 049 653` are accepted. |
| `ch_chid` | `CH02030216152` | The former 11-digit commercial-register number (CH-ID); `CH-020.3.021.615-2` is accepted. |
| `ch_ehraid` | `460530` | Internal id of the federal register office, one per register entry. |
| `vat` | `CHE101049653` | Swiss VAT numbers are UIDs. A company in a VAT group is taxed under the group's number; that number is not added to the members, so they stay separate records. |

A company with two head offices (Nestlé AG in Cham and Nestlé S.A. in Vevey)
has one UID and two register entries: the record carries both EHRA-IDs and
CH-IDs, the entry with the lower EHRA-ID gives the name, and the second seat
appears as an address of type `other`.

## Fields

- **Legal name** (`names.legal`): the commercial register's primary entry,
  as Zefix REST, Zefix on LINDAS, the UID register or the cantonal excerpt
  (in this order) publish it; the gazette, GLEIF and other sources never
  replace it, whatever order the sources are refreshed in. Swiss firms often
  have equal-ranking versions in several languages (Nestlé AG / Nestlé S.A. /
  Nestlé Ltd.): the others are in `names.translations`, and other sources'
  forms (GLEIF's `NESTLÉ S.A.`) in `names.alternates`, each with its `source`.
- **Legal form**: the eCH-0097 code as `local_code` (`0106`), the name in the
  canton's language as `local_name` (Aktiengesellschaft, société anonyme,
  società anonima), the ISO 20275 ELF code and the category. Examples: AG / SA
  `MVII`, GmbH / Sàrl / Sagl `3EKS`, Genossenschaft `QSI2`, Verein `H781`,
  Stiftung `2JZ4`, Einzelunternehmen `AZA0`, Kollektivgesellschaft `MRSY`,
  Kommanditgesellschaft `CQMY`, Swiss branch `UNA9`, branch of a foreign
  company `JB25`, federal administration `2XJA`.
- **Status**: `active`; `in_liquidation` (status `BEING_CANCELLED`, or "in
  Liquidation / en liquidation / in liquidazione" in the name); `dissolved`
  after deletion; `merged` when the company was taken over. `local_value` keeps
  the source's wording and `since` the deletion date.
- **Addresses**: the registered address with the BFS municipality number,
  and the postal address (PO box) from the UID register.
- **Purpose**: in the register's language (`de`, `fr` or `it`).
- **Capital**: nominal capital, and paid-in capital from the SOGC.
- **Relationships**: `auditor`, `merged_into`, `absorbed`, `branch`,
  `head_office` (Zefix REST).
- **Activities**: NOGA codes, with their NACE class, when the UID register
  publishes them.
- **People** (`include=people`): every officer and signatory the cantonal
  excerpt lists, current and former, with role (`chair`, `director`, `ceo`,
  `managing_director`, `partner`, `auditor`, `liquidator`, `secretary`,
  `signatory`, `member`) and the register's own wording, signing authority
  (`individual`, `joint_two`, `joint`, `procuration_individual`,
  `procuration_joint_two`, `none`), since/until from the register journal,
  residence and origin or nationality. Officer changes published in the SOGC
  are also in `events` with the people who joined or left. The register
  publishes no birth dates and Cormorant stores none.
- **Events** (`include=events`): one entry per change and publication, with
  the publication link on shab.ch, the publication and journal numbers and
  dates, and details such as the old and new name or capital, the other
  company of a merger, or the people of an officer change.

```sh
curl -s "https://api.cormorant.ch/v1/companies/ch_uid:CHE-105.909.036?include=people,events" \
  -H "Authorization: Bearer $CORMORANT_API_KEY"
```

## Freshness

| Field group | Refreshed after | Kept current by |
|---|---|---|
| core (name, legal form, status, address, purpose, capital) | 24 hours | the SOGC daily feed |
| people | 7 days | officer changes in the SOGC feed |
| events | 24 hours | the SOGC daily feed |
| relationships | 24 hours | Zefix REST |

The gazette publishes every register change on the day it takes effect for
third parties. Cormorant reads its daily feed and applies the publications
to companies already in the register, without your request. LINDAS and the
UID register update daily. A company that is not in LINDAS has been deleted
or is not in the commercial register: the UID register and Zefix REST still
know it.

## Activating Zefix REST

Zefix REST adds deleted companies, capital, former names, mergers, branches
and audit firms. It stays inactive until credentials are set:

1. The operator requests credentials from the Federal Office of the
   Commercial Register (zefix@bj.admin.ch). The office issues them without charge.
2. In Mission Control, open **Company data → Sources → zefix_rest** and
   enter the **username** and **password**. Credentials are encrypted at
   rest, never shown again and never logged.
3. Switch the source **on**. The source card shows its health and canaries
   (Nestlé, UBS Group). A wrong password shows as error class `auth`.

`GET /v1/companies/sources` then lists `zefix_rest` as active.

## Limits

- The VD and GE portals have not yet been checked against production
  responses; ZH (chregister.ch) has.
- Cantonal excerpts exist for the cantons in the source's URL table (ZH,
  BE, LU, ZG, BS, TI, VD, GE) and those the operator adds in its options;
  elsewhere officers come from the SOGC events only.
- Cantonal excerpts need the premium routes (residential proxy or rendering). Without
  it the source answers `not_configured`.
- Some French-speaking register offices write officer changes as prose, not
  as labelled lists. Cormorant reads the usual sentences ("n'est plus
  administrateur", "Nouvel organe de révision: …", "Signature individuelle
  est conférée à …"). Unusual wording yields an officer-change event without
  the people.
- The UID register allows about 20 requests per minute. Bulk lookups take
  their time, and the register answers in the meantime.
