Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions domain-skills/crbr-podatki-gov-pl/search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# crbr.podatki.gov.pl — CRBR beneficial-owners search

Poland's Central Register of Beneficial Owners (Centralny Rejestr
Beneficjentów Rzeczywistych). Public search UI at
`https://crbr.podatki.gov.pl/adcrbr/#/wyszukaj` (Angular SPA, PrimeNG).

## Private API — skip the DOM entirely

The SPA calls one endpoint for entity search, and it works from plain
HTTP with `reCaptchaToken: "0"` (the captcha is not enforced server-side
as of 2026-06):

```python
import json
r = http_post(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace undefined http_post helper

This skill tells agents to call http_post, but the harness only provides http_get in helpers.py and no other domain skill defines http_post (checked with rg "http_post"). A future agent following this example will hit NameError before reaching the documented API; the snippet should either show a local urllib.request.Request(..., method="POST") pattern or add/use an actual helper.

Useful? React with 👍 / 👎.

"https://crbr.podatki.gov.pl/adcrbr/api/wyszukajSpolke",
json={
"kontekstWyszukania": 1, # 1 = entity search (by NIP/KRS/name)
"nip": "5213107693", # or "krs": "0000125836"
"dataOd": "2026-06-06", # date range of register entries
"dataDo": "2026-06-06",
Comment on lines +20 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid hard-coding the current-date search window

The example hard-codes 2026-06-06 while the surrounding text says this should be today to fetch the current entry. Once agents reuse the skill after June 6, 2026, this payload will request the register state for that old date rather than the current default portal search, producing stale beneficial-owner results; use a computed date.today().isoformat() value instead.

Useful? React with 👍 / 👎.

"reCaptchaToken": "0",
"czasPobraniaDanych": 1780703336220, # Date.now() ms; not validated
},
)
```

- `dataOd == dataDo == today` → the **current** entry only (this is what
the portal's own "Wyszukaj" does by default).
- `dataOd = "2019-10-13"` (register start) → **full history**, one entry
per `informacjeOSpolkachIBeneficjentach[]` item, oldest first. Each has
`dataPoczatkuPrezentacji` / `dataKoncaPrezentacji` and
`listaBeneficjentow[]`.
- Owner fields: `imiePierwsze`, `nazwisko`, `pesel` (null for foreigners),
`dataUrodzenia` (set when pesel is null), `obywatelstwo` is an **array
of `{kodKraju, nazwa}`**, `panstwoZamieszkania` an object of the same
shape. Control description lives in
`informacjeOUdzialeLubUprawnieniach[].uprWlasPosrednie` (free text).
- No entry for the NIP → `informacjeOSpolkachIBeneficjentach: []`, still
HTTP 200.
- Wrong endpoint paths return Spring-style `{"status":404,...}` JSON —
the backend is alive, your path is wrong.

## UI traps (if you must drive the SPA)

- The search form's radio groups disable competing inputs: filling the
NIP textbox disables KRS/name/PESEL fields and enables "Wyszukaj".
- **CDP-dispatched compositor clicks on "Wyszukaj" do nothing** (no XHR
fires). Click the button via JS instead:
`[...document.querySelectorAll('button')].find(b => b.textContent.includes('Wyszukaj')).click()`.
- In a fresh headless Chromium the search XHR can fail with status 0
even though the same request succeeds from curl — prefer the API.
- The filing app under the same origin (`api/slownik/*`, `api/address/*`)
is a different module; the search bundle is lazy-loaded, so grepping
`main.*.js` for the search endpoint finds nothing.